LoginSignup
0
0

More than 1 year has passed since last update.

Ruby 06 画像の生成(総合実習)

Last updated at Posted at 2021-08-17

注意

このファイルを使う際には、必ず同じ階層に「colorName.csv」を配置してください。
配置していない場合、カーラネームでの色の指定ができません。

設定用関数

設定用関数です。
描画には関係ありません。

init関数

[引数] スクリーンサイズ x座標(デフォルト 1980), スクリーンサイズ y座標(デフォルト 1080)
[説明]
初期化用関数。draw関数内で必ず最初に使用してください。
デフォルトサイズ 1980x1080

pset関数

[引数] 点を打つ x座標, 点を打つ y座標, 色(デフォルト 0, 0, 0), 透明度(0.0)
[説明]
指定した座標に指定した色、透明度で点を打ちます。

writeimage関数

[引数] 書き込むファイル名
[説明]
データをppmファイルに書き込みます。ppmファイルのみ指定できます。

計算用関数

描画に使う計算をするための関数です。

deg2rad関数

[引数] 弧度法に変換したい角度(度数法)
[説明]
度数法(deg)を弧度法(rad)に変換します。
Math.sin, Math.cosなどの引数に度数法を指定したいときに使用します。

getColor関数

[引数] カラーコード(文字列)
[説明]
カラーコードもしくはカラーネームをrgbに変換します。「#ffffff」のような形で指定してください。
カラーネームについては
https://www.webcreatorbox.com/webinfo/color-name
を参照してください。

描画用関数

図形を描画するための関数です。

background関数

[引数] 色(デフォルト 0, 0, 0), 透明度(0.0)
[説明]
背景を描画します。

line関数

[引数] 開始 x座標, 開始 y座標, 終点 x座標, 終点 y座標, 幅, 色(デフォルト 0, 0, 0), 透明度(0.0)
[説明]
線を描画します。

circle関数

[引数] 中心 x座標, 中心 y座標, 半径, 色(デフォルト 0, 0, 0), 透明度(0.0)
[説明]
塗りつぶされた円を描画します。
枠線を描画したい場合はdonut関数を使用して下さい。

ellipse関数

[引数] 中心 x座標, 中心 y座標, 横(x軸方向)の半径, 縦(y軸方向)の半径, 回転角度(度数法)(デフォルト 0.0), 色(デフォルト 0, 0, 0), 透明度(0.0)
[説明]
塗りつぶされた楕円を描画します。
回転角度には度数法を指定します。

donut関数

[引数] 中心 x座標, 中心 y座標, 半径1, 半径2 色(デフォルト 0, 0, 0), 透明度(0.0)
[説明]
ドーナツ型を描画します。
半径2 < 半径1となるように引数を指定してください

triangle関数

[引数] 頂点 x座標1, 頂点 y座標1, 頂点 x座標2, 頂点 y座標2, 頂点 x座標3, 頂点 y座標3, 色(デフォルト 0, 0, 0), 透明度(0.0)
[説明]
三角形を描画します。

rect関数

[引数] 中心 x座標, 中心 y座標, 幅, 高さ, 色(デフォルト 0, 0, 0), 透明度(0.0)
[説明]
長方形を描画します。

trapezoid関数

[引数] 中心 x座標, 中心 y座標, 上底の長さ, 下底の長さ, 高さ, 色(デフォルト 0, 0, 0), 透明度(0.0)
[説明]
台形を描画します。

rhombus関数

[引数] 中心 x座標, 中心 y座標, 幅, 高さ, 色(デフォルト 0, 0, 0), 透明度(0.0)
[説明]
ひし形を描画します。

star関数

[引数] 中心 x座標, 中心 y座標, 外接円の半径, 頂点の数, 回転角度(弧度法)(デフォルト 0.0) 色(デフォルト 0, 0, 0), 透明度(0.0)
[説明]
星形を描画します。
回転角度には弧度法を指定してください。
[参考] http://blog.livedoor.jp/reona396/archives/54602822.html

polygon関数

[引数] 中心 x座標, 中心 y座標, 外接円の半径, 頂点の数, 回転角度(弧度法)(デフォルト 0.0) 色(デフォルト 0, 0, 0), 透明度(0.0)
[説明]
正多角形を描画します。
回転角度には弧度法を指定してください。
[参考] http://blog.livedoor.jp/reona396/archives/54602822.html

convex関数

[引数] 頂点 x座標の配列, 頂点 y座標の配列, 回転角度(弧度法)(デフォルト 0.0) 色(デフォルト 0, 0, 0), 透明度(0.0)
[説明]
凸多角形を描画します。
凹みがある場合は描写できません。

メイン関数

描画用の処理を書くための関数です。

draw関数

[説明]
init関数を一番最初に記述してください。
最後にwriteimage関数で画像を描画します。

ファイルのダウンロード

右上の緑の「Code」から「Download ZIP」を選択するとダウンロードできます。

全体のプログラム

drawImg.rb
# drawImg.rb

#
# ========== settings ==========
#

require "csv"


Pixel = Struct.new(:r, :g, :b)

# init func
# [args] screenSizeX, screenSizeY
def init(screenSizeX = 1980, screenSizeY = 1080)

    # create colorNameArray
    # [Reference] https://www.webcreatorbox.com/webinfo/color-name
    $colorName = CSV.read("colorName.csv")

    # default screenSize
    $screenX = screenSizeX
    $screenY = screenSizeY

    # default var draw area
    $i0 = 0
    $i1 = $screenX
    $j0 = 0
    $j1 = $screenY

    # define goldenRatio
    $goldenRatio = 1.618

    # create imgArray
    $img = Array.new($screenY) do
        Array.new($screenX) do
            Pixel.new(255, 255, 255)
        end
    end
end

# pointSet func
# [args] x, y, color, a
def pset(x, y, color = [255, 255, 255], a = 0.0)
    # error
    if x < 0 || x >= $screenX || y < 0 || y >= $screenY
        return
    end

    r = color[0]
    g = color[1]
    b = color[2]

    $img[y][x].r = ($img[y][x].r * a + r * (1.0 - a)).to_i
    $img[y][x].g = ($img[y][x].g * a + g * (1.0 - a)).to_i
    $img[y][x].b = ($img[y][x].b * a + b * (1.0 - a)).to_i
end

# writeImage func
# [args] filename
def writeimage(name)
    s = "P6\n" + $screenX.to_s + " " + $screenY.to_s + "\n255"
    open(name, "wb") do |f|
        f.puts(s)
        $img.each do |a|
            a.each do |p|
                f.write(p.to_a.pack("ccc"))
            end
        end
    end
    return true
end

#
# ========== calc func ==========
#

# deg => rad func
# [args] theta(deg)
def deg2rad(theta)
    return theta * Math::PI / 180.0
end

# judge isinside func
# [args] x, y, arrayX, arrayY
# [Reliance] oprod
def isinside(x, y, ax, ay)
    (ax.length-1).times do |i|
        if oprod(ax[i+1]-ax[i], ay[i+1]-ay[i], x-ax[i], y-ay[i]) < 0
            return false
        end
    end
    return true
end

# get outer product
# [args] a, b, c, d
def oprod(a, b, c, d)
    return a*d - b*c
end

# getColor (colorCode to rgba)
# [args] colorCode
def getColor(colorCode)
    rgb = Array.new()

    # colorName check
    $colorName.each_index do |i|
        if colorCode === $colorName[i][0]
            colorCode = $colorName[i][1]
            break
        end
    end

    # convert colorCode
    if colorCode[0] === "#"
        1.step(6, 2) do |i|
            str = colorCode[i] + colorCode[i+1]
            rgb.push(str.to_i(16))
        end
    else
        rgb.push(0)
        rgb.push(0)
        rgb.push(0)
    end
    return rgb
end

# set draw area func
# [args] x0, x1, y0, y1
def setDrawArea(x0, x1, y0, y1)
    $i0 = x0.to_i
    $i1 = x1.to_i
    $j0 = y0.to_i
    $j1 = y1.to_i
end

#
# ========== draw shape func ==========
#

# draw background func
# [args] color, a
def background(color = [0, 0, 0], a = 0.0)
    $screenY.times do |j|
        $screenX.times do |i|
            pset(i, j, color, a)
        end
    end
end

# draw line
# [args] startX, startY, endX, endY, width, color, a
# [Reliance] convex
def line(x0, y0, x1, y1, w, color = [0, 0, 0], a = 0.0)
    dx = y1 - y0
    dy = x0 - x1
    n = 0.5 * w / Math.sqrt(dx**2 + dy**2)
    dx *= n
    dy *= n
    convex([x0-dx, x0+dx, x1+dx, x1-dx, x0-dx], [y0-dy, y0+dy, y1+dy, y1-dy, y0-dy], color, a)
end

# draw circle func
# [args] centerX, centerY, radius, color, a
def circle(x, y, rad, color = [0, 0, 0], a = 0.0)
    setDrawArea(x-rad, x+rad, y-rad, y+rad)

    $j0.step($j1) do |j|
        $i0.step($i1) do |i|
            if (i - x)**2 + (j - y)**2 < rad**2
                if block_given?
                    yield(i, j)
                else
                    pset(i, j, color, a)
                end
            end
        end
    end
end

# draw ellipse func
# [args] centerX, centerY, radiusX, radiusY, rotateTheta(deg), color, a
def ellipse(x, y, radX, radY, theta = 0.0, color = [0, 0, 0], a = 0.0)
    d = (if radX > radY then radX else radY end)
    setDrawArea(x-d, x+d, y-d, y+d)

    thetaRad = theta * Math::PI / 180
    $j0.step($j1) do |j|
        $i0.step($i1) do |i|
            dx = i - x
            dy = j - y
            px = dx * Math.cos(thetaRad) - dy * Math.sin(thetaRad)
            py = dx * Math.sin(thetaRad) + dy * Math.cos(thetaRad)
            if (px/radX)**2 + (py/radY)**2 < 1.0
                if block_given?
                    yield(i, j)
                else
                    pset(i, j, color, a)
                end
            end
        end
    end
end

# draw donut func
# [args] centerX, centerY, radius1, radius2, color, a
def donut(x, y, rad1, rad2, color = [0, 0, 0], a = 0.0)
    setDrawArea(x-rad1, x+rad1, y-rad1, y+rad1)

    $j0.step($j1) do |j|
        $i0.step($i1) do |i|
            d = (i - x)**2 + (j - y)**2
            if rad2**2 < d && d < rad1**2
                if block_given?
                    yield(i, j)
                else
                    pset(i, j, color, a)
                end
            end
        end
    end
end

# draw triangle func
# [args] x0, y0, x1, y1, x2, y2, color, a
# [Reliance] convex
def triangle(x0, y0, x1, y1, x2, y2, color = [0, 0, 0], a = 0.0)
    convex([x0, x1, x2, x0], [y0, y1, y2, y0], color, a)
    convex([x0, x2, x1, x0], [y0, y2, y1, y0], color, a)
end

# draw rect func
# [args] centerX, centerY, width, height, color, a
def rect(x, y, w, h, color = [0, 0, 0], a = 0.0)
    setDrawArea(x-0.5*w, x+0.5*w, y-0.5*h, y+0.5*h)

    $j0.step($j1) do |j|
        $i0.step($i1) do |i|
            if block_given?
                yield(i, j)
            else
                pset(i, j, color, a)
            end
        end
    end
end

# draw trapezoid func
# [args] centerX, centerY, topLength, bottomLength, height, color, a
# [Reliance] convex
def trapezoid(x, y, u, b, h, color = [0, 0, 0], a = 0.0)
    convex([x+u/2, x+b/2, x-b/2, x-u/2, x+u/2], [y-h/2, y+h/2, y+h/2, y-h/2, y-h/2], color, a)
end

# draw rhombus func
# [args] centerX, centerY, width, height, color, a
# [Reliance] convex
def rhombus(x, y, w, h, color = [0, 0, 0], a = 0.0)
    convex([x, x+w, x, x-w, x], [y-h, y, y+h, y, y-h], color, a)
end

# draw star func
# [args] centerX, centerY, radius, vertexNum, theta, color, a
# [Reliance] convex
# [Reference] http://blog.livedoor.jp/reona396/archives/54602822.html
def star(x, y, rad, vertexNum, theta = 0.0, color = [0, 0, 0], a = 0.0)
    rOut = rad
    rIn = rad / 2.0
    vertexNum *= 2
    (vertexNum/2).times do |i|
        x1 = rOut * Math.cos(deg2rad((360 / vertexNum * i * 2) - 90 + theta).to_f) + x
        x2 = rIn * Math.cos(deg2rad((360 / vertexNum * (i * 2 + vertexNum + 1)) - 90 + theta).to_f) + x
        x3 = x
        x4 = rIn * Math.cos(deg2rad((360 / vertexNum * (i * 2 + vertexNum - 1)) - 90 + theta).to_f) + x
        y1 = rOut * Math.sin(deg2rad((360 / vertexNum * i * 2) - 90 + theta).to_f) + y
        y2 = rIn * Math.sin(deg2rad((360 / vertexNum * (i * 2 + vertexNum + 1)) - 90 + theta).to_f) + y
        y3 = y
        y4 = rIn * Math.sin(deg2rad((360 / vertexNum * (i * 2 + vertexNum - 1)) - 90 + theta).to_f) + y
        convex([x1, x2, x3, x4, x1], [y1, y2, y3, y4, y1], color, a)
    end
end

# draw polygon func
# [args] centerX, centerY, radius, vertexNum, theta, color, a
# [Reliance] convex
# [Reference] http://blog.livedoor.jp/reona396/archives/54602822.html
def polygon(x, y, rad, vertexNum, theta = 0.0, color = [0, 0, 0], a = 0)
    ax = Array.new()
    ay = Array.new()
    vertexNum.times do |i|
        ax.push(rad * Math.cos(deg2rad((360 / vertexNum * i) - 90).to_f) + x)
        ay.push(y1 = rad * Math.sin(deg2rad((360 / vertexNum * i) - 90).to_f) + y)
    end
    ax.push(rad * Math.cos(deg2rad(-90 + theta).to_f) + x)
    ay.push(rad * Math.sin(deg2rad(-90 + theta).to_f) + y)
    convex(ax, ay, color, a)
end

# draw convex func
# [args] arrayX, arrayY, r, g, b, a
# [!Caution!] Enter counterclockwise
# [Reliance] isinside
def convex(ax, ay, color = [0, 0, 0], a = 0.0)
    setDrawArea(ax.min, ax.max, ay.min, ay.max)

    $j0.step($j1) do |j|
        $i0.step($i1) do |i|
            if isinside(i, j, ax, ay)
                if block_given?
                    yield(i, j)
                else
                    pset(i, j, color, a)
                end
            end
        end
    end
end

# draw func (drawPicture)
# [args] none
def draw
    #init
    init()

    # ここに処理を記述

    # write
    writeimage("img.ppm")
    return true
end

draw()

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0