裏 RjpWiki

Julia ときどき R, Python によるコンピュータプログラム,コンピュータ・サイエンス,統計学

Plots で使える描画関数に糖衣をかぶせた自作描画関数群

2021年08月10日 | ブログラミング

描画関数を組み合わせて「麻の葉格子」を描く】で使った自作描画関数群

# ファイル名 plotter.jl

using Plots

# 開始
function plotbegin(; w = 600, h = 600)
    pyplot(grid=false, aspect_ratio=1, size=(w, h),
        xlabel="", ylabel="", label="")
    plt = plot(showaxis=false)
end

# プロット領域((x1, y1), (x2, y2) を対角座標とする矩形内)の設定
function plotlimit(x1, y1, x2, y2)
    plot!(xlims=(x1, x2), ylims=(y1, y2))
end

# 終了
function plotend()
    plot!()
end

# 座標ベクトル x, y による折線
function plotline(x::Vector{Float64}, y::Vector{Float64};
        col=:black, lty=:solid, lwd=1)
    plot!(x, y, linecolor=col, linestyle=lty, linewidth=lwd)
end

# (x1, y1) - (x2, y2) の線分
function plotline(x1, y1, x2, y2; col=:black, lty=:solid, lwd=1)
    plot!([x1, x2], [y1, y2], linecolor=col, linestyle=lty, linewidth=lwd)
end

# (x1, y) - (x2, y) の水平線分
function plothline(x1, x2, y; col=:black, lty=:solid, lwd=1)
    plot!([x1, x2], [y, y], linecolor=col, linestyle=lty, linewidth=lwd)
end

# (x, y1) - (x, y2) の垂直線分
function plotvline(x, y1, y2; col=:black, lty=:solid, lwd=1)
    plot!([x, x], [y1, y2], linecolor=col, linestyle=lty, linewidth=lwd)
end

# (x1, y1), (x2, y2) を対角座標とする矩形
function plotbox(x1, y1, x2, y2; col=:black, lty=:solid, lwd=1, fcol="")
    if fcol == ""
        plot!([x1, x2, x2, x1, x1], [y1, y1, y2, y2, y1], linecolor=col,
              linestyle=lty, linewidth=lwd)
    else
        plot!([x1, x2, x2, x1, x1], [y1, y1, y2, y2, y1], linecolor=col,
              linestyle=lty, seriestype=:shape, linewidth=lwd, fillcolor=fcol)
    end
end

# (ox, oy) を原点とする半径 r の円(円弧)。fcol を指定すると塗りつぶし。
function plotcircle(ox, oy, r; startangle=0, endangle=360,
                    col=:black, lty=:solid, lwd=1, fcol="")
    plotellipse(ox, oy, r, r, φ=0, startangle=startangle,
                endangle=endangle, col=col, lty=lty, lwd=lwd, fcol=fcol)
end

# 度をラジアンに変換する
radian(degree) = degree / 180 * π

# (ox, oy) を中心,ra, rb を半径とする楕円(楕円弧)。fcol を指定すると塗りつぶし。
function plotellipse(ox, oy, ra, rb; φ=0, startangle=0, endangle=360,
                     length=100, col=:black, lty=:solid, lwd=1, fcol="")
    θ = vcat(range(radian(startangle), radian(endangle),
              length=length), radian(endangle))
    if φ == 0
        if fcol == ""
            plot!(ra .* cos.(θ) .+ ox, rb .* sin.(θ) .+ oy,
                  linecolor=col, linestyle=lty, linewidth=lwd)
        else
            plot!(ra .* cos.(θ) .+ ox, rb .* sin.(θ) .+ oy,
                  linecolor=col, linestyle=lty, linewidth=lwd,
                  seriestype=:shape, fillcolor=fcol)
        end
    else
        x = ra .* cos.(θ)
        y = rb .* sin.(θ)
        φ = radian(φ)
        cosine = cos(φ)
        sine = sin(φ)
        if fcol == ""
            plot!(cosine .* x .- sine .* y .+ ox,
                  sine .* x .+ cosine .* y .+ oy,
                  linecolor=col, linestyle=lty, linewidth=lwd)
        else
            plot!(cosine .* x .- sine .* y .+ ox,
                  sine .* x .+ cosine .* y .+ oy,
                  linecolor=col, linestyle=lty, linewidth=lwd,
                  seriestype=:shape, fillcolor=fcol)
        end
    end
end

# 任意の多角形。fcol を指定すると塗りつぶし。
function plotpolygon(x, y; col=:black, lty=:solid, lwd=1, fcol="")
    x = vcat(x, x[1])
    y = vcat(y, y[1])
    if fcol == ""
        plot!(x, y, linecolor=col, linestyle=lty, linewidth=lwd)
    else
        plot!(x, y, linecolor=col, linestyle=lty, linewidth=lwd,
              seriestype=:shape, fillcolor=fcol)
    end
end

# (x1, y1) を描き始め,一辺の長さ l の正 n 多角形。fcol を指定すると塗りつぶし。
function plotpolygon1(x1, y1, l, n; col=:black, lty=:solid, lwd=1, fcol="")
    θ = range(0, 2π, length=n+1)
    x = fill(float(x1), n+1)
    y = fill(float(y1), n+1)
    for i = 2:n
        x[i] = x[i-1]+l*cos(θ[i])
        y[i] = y[i-1]+l*sin(θ[i])
    end
    if fcol == ""
        plot!(x, y, linecolor=col, linestyle=lty, linewidth=lwd)
    else
        plot!(x, y, linecolor=col, linestyle=lty,
              seriestype=:shape, fillcolor=fcol, linewidth=lwd)
    end
end

# (ox, oy) を中心,r を半径とする円に内接する正 n 多角形。fcol を指定すると塗りつぶし。
function plotpolygon2(ox, oy, r, n; φ=90, col=:black, lty=:solid, lwd=1, fcol="")
    θ = range(0, 2π, length=n+1) .+ radian(φ)
    if fcol == ""
        plot!(r .* cos.(θ) .+ ox, r .* sin.(θ) .+ oy,
              linecolor=col, linestyle=lty, linewidth=lwd)
    else
        plot!(r .* cos.(θ) .+ ox, r .* sin.(θ) .+ oy,
              linecolor=col, linestyle=lty, linewidth=lwd,
              seriestype=:shape, fillcolor=fcol)
    end
end

# (x1,y1) - (x2, y2) の矩形範囲に格子を描く。間隔は wx, wy。
function plotgrid(x1, y1, x2, y2, wx; wy=wx, col=:gray, lty=:dot, lwd=1)
    X1 = min(x1, x2)
    X2 = max(x1, x2)
    Y1 = min(y1, y2)
    Y2 = max(y1, y2)
    for i = 0:fld(abs(X2-X1), wx)
        plot!([X1+wx*i, X1+wx*i], [Y1, Y2], linecolor=col,
              linestyle=lty, linewidth=lwd)
    end
    for i = 0:fld(abs(y2-y1), wy)
        plot!([X1, X2], [Y1+wy*i, Y1+wy*i], linecolor=col,
              linestyle=lty, linewidth=lwd)
    end
end

# 二点 (x1, y1), (x2, y2) を通る半径 r の円弧(短い方)を描く。
# 短い方の円弧も,円の中心が 2 つあるので,x1 = x2 の場合は,右か左いずれの中心を使うかを :right, :left で示す。
# x1 ≠ x2 の場合は,上か下いずれの中心を使うかを :upper, :lower で示す。
function plotarc(x1, y1, x2, y2, r; udrl="", col=:black, lwd=1)
    function adjust(φ, x1, y1, x3, y3)
        if x1 >= x3 && y1 >= y3 # 第1象限
            return φ
        elseif x1 >= x3 && y1 < y3 # 第4象限
            return 360-φ
        elseif x1 < x3 && y1 >= y3 # 第2象限
            return 180-φ
        elseif x1 < x3 && y1 < y3 # 第3象限
            return 180+φ
        end
    end
    if y1 > y2
        x1, y1, x2, y2 = x2, y2, x1, y1
    end
    x31 = x32 = y31 = y32 = NaN
    if x1 == x2
        w = r^2 - (y2 - y1)^2 / 4
        if w >= 0
            t0 = sqrt(w)
            x31 = x1 + t0
            x32 = x1 - t0
            y31 = y32 = (y1 + y2) / 2
            θ = asind(abs(y2 - y32) / r)
            if udrl == :right
                plotcircle(x31, y31, r, startangle=180 - θ, endangle=180 + θ, col=col, lwd=lwd)
            elseif udrl == :left
                plotcircle(x32, y32, r, startangle=-θ, endangle=θ, col=col, lwd=lwd)
            else
                error("if x1 == x2, udrl must be ':right' or ':left'")
            end
        end
    else
        t1 = x1^2 - x2^2 + y1^2 - y2^2
        t5 = x1 - x2
        t2 = y2 - y1
        t3 = t5^2 + t2^2
        t4 = t3 - 4r^2
        w = -t3*t4
        if w > 0
            t6 = y1/2 + y2/2
            t7 = sqrt(w)*t5/2t3
            y31 = t6 - t7
            y32 = t6 + t7
            if y31 < y32
                y31, y32 = y32, y31
            end
            x31 = (t1 + 2t2*y31)/2t5
            x32 = (t1 + 2t2*y32)/2t5
            posy1 = y31 - (y2 - y1)/(x2 - x1)*(x31 - x1) - y1
            posy2 = y32 - (y2 - y1)/(x2 - x1)*(x32 - x1) - y1
            if udrl == :upper
                x3, y3 = x31, y31
            else#if udrl == :lower
                x3, y3 = x32, y32
            end
            #println("(x1, y1) = ($x1, $y1),  (x2, y2) = ($x2, $y2),  (x3, y3) = ($x3, $y3)")
            φ = adjust(asind(abs(y1 - y3) / r), x1, y1, x3, y3)
            θ = adjust(asind(abs(y2 - y3) / r), x2, y2, x3, y3)
            θ - φ > 180 && (θ -= 360)
            φ - θ > 180 && (φ -= 360)
            #println("posy1 = $posy1,  posy2 = $posy2,  θ = $θ,  φ = $φ")
            plotcircle(x3, y3, r, startangle=φ, endangle=θ, col=col, lwd=lwd)
        end
    end
    x31, y31, x32, y32
end

コメント    この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« 描画関数を組み合わせて「麻... | トップ | Julia で亀甲ベースの格子模... »
最新の画像もっと見る

コメントを投稿

ブログラミング」カテゴリの最新記事