SSブログ

[.NET]関数(y=f(x))のグラフをImageに描画する [Programming .NET Tips]

[ポイント]
・関数(y=f(x))の呼び出しは、デリゲート経由で行います。
 これにより、描画メソッド(DrawFunctionメソッド)を変更することなく、
 関数(y=f(x))を切替えることができます。
・非関数(xとyが1対1に対応していない)には対応していません。
 例えば、x2+y2=r2のような円を表すグラフは描画できません。
・Graphics.DrawLineメソッドで、一つ前の座標との直線を描画している為、
 連続していない関数(離散型)では一部正しく描画されないことがあります。
 例えば、y=tan(x)の場合、x=π/2で縦線が描画されます。
''' <summary>
''' 関数(y=f(x))のデリゲート
''' </summary>
''' <param name="x">入力</param>
''' <returns>出力</returns>
''' <remarks></remarks>
Public Delegate Function FuncHandler(ByVal x As IntegerAs Integer

''' <summary>
''' 関数(y=f(x))のグラフをイメージに描画する。
''' </summary>
''' <param name="targetImage">描画対象のイメージ</param>
''' <param name="fnc">関数(y=f(x))</param>
''' <param name="xFrom">X座標の最小値</param>
''' <param name="xTo">X座標の最大値</param>
''' <remarks></remarks>
Public Shared Sub DrawFunction( _
    ByVal targetImage As Image, ByVal fnc As FuncHandler, _
    ByVal xFrom As IntegerByVal xTo As Integer)

    Dim g As Graphics = Nothing

    Try
        g = Graphics.FromImage(targetImage)

        '描画領域を初期化(白で塗りつぶす)
        g.FillRectangle(Brushes.White, 0, 0, _
            targetImage.Width, targetImage.Height)

        '描画領域の原点を中央に移動
        Dim xMax As Integer = targetImage.Width * 0.5
        Dim xMin As Integer = -1 * xMax
        Dim yMax As Integer = targetImage.Height * 0.5
        Dim yMin As Integer = -1 * yMax
        g.TranslateTransform(xMax, yMax)
        '描画領域のY座標の向きを逆にする(Y座標の上方向をプラスにする)
        g.ScaleTransform(1, -1)

        '格子を描画する(水平線)
        For y As Single = 0 To yMax Step 10
            g.DrawLine(Pens.Cyan, xMin, y, xMax, y)
        Next
        For y As Single = 0 To yMin Step -10
            g.DrawLine(Pens.Cyan, xMin, y, xMax, y)
        Next

        '格子を描画する(垂直線)
        For x As Single = 0 To xMax Step 10
            g.DrawLine(Pens.Cyan, x, yMin, x, yMax)
        Next
        For x As Single = 0 To xMin Step -10
            g.DrawLine(Pens.Cyan, x, yMin, x, yMax)
        Next

        'X軸を描画
        g.DrawLine(Pens.Blue, xMin, 0, xMax, 0)
        'Y軸を描画
        g.DrawLine(Pens.Blue, 0, yMin, 0, yMax)

        '関数のグラフを描画
        For x As Integer = xFrom To xTo
            Try
                g.DrawLine( _
                    Pens.Black, x - 1, _
                    fnc.Invoke(x - 1), x, fnc.Invoke(x))
            Catch ex As ArithmeticException
                'ゼロ除算、数値演算のオーバーフロー、
                '定義されていない演算エラーは無視する
            End Try
        Next
    Finally
        If Not (g Is NothingThen
            g.Dispose()
        End If
    End Try
End Sub
[VB.NET]関数のグラフをImageに描画する例

(1)PictureBoxに、一次関数(y=2x)のグラフを描画する例
・上記で定義したメソッド(DrawFunction)の使用例を以下に示します。
 まずは、一次関数(y=2x)を定義します。
''' <summary>
''' 関数(一次関数)
''' </summary>
''' <param name="x">入力</param>
''' <returns>出力</returns>
''' <remarks></remarks>
Public Function fnc1(ByVal x As IntegerAs Integer
    Return x * 2
End Function
[VB.NET]例:一次関数の定義

・適当なイベント処理内で、DrawFunctionメソッドを呼ぶ処理を記述します。
 DrawFunctionメソッドに渡す引数は、
 ・グラフを描画するImageインスタンス
 ・一次関数(y=2x)のデリゲート (※デリゲートとはメソッドの参照を格納する変数、型です。)
 ・X座標の範囲(From、To)
 です。
 [デリゲートについて]
  .NETでは、メソッドの参照を変数に格納し、変数経由でメソッドに
  アクセスすることができます。 (デリゲート変数)
  この例では、一次関数の定義をデリゲート変数に格納し、DrawFunctionメソッドに渡します。
  メソッドの参照はAddressOf演算子で取得します。
  デリゲート変数はFuncHandler型で定義し、fnc1と関連付けします。
Private Sub Button1_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Button1.Click
    Dim img As New Bitmap(Me.PictureBox1.Width, Me.PictureBox1.Height)

    '関数の参照をデリゲート変数に格納する
    '※関数を変更する場合は、デリゲート変数の中身を変更する。
    Dim f As New FuncHandler(AddressOf Me.fnc1)
    '関数のグラフを描画する。
    DrawFunction(img, f, img.Width * -0.5, img.Width * 0.5)

    Me.PictureBox1.Image = img
End Sub
[VB.NET]DrawFunctionメソッドの呼び出し
実行結果
一次関数

(2)PictureBoxに、二次関数のグラフを描画する例
・デリゲート変数の内容を、二次関数のデリゲートに置き換えるだけで、描画内容を変更できます。
''' <summary>
''' 関数(二次関数)
''' </summary>
''' <param name="x">入力</param>
''' <returns>出力</returns>
''' <remarks></remarks>
Public Function fnc1(ByVal x As IntegerAs Integer
    Return 0.05 * (x - 10) * (x + 50)
End Function
[VB.NET]関数を二次関数で定義した場合
実行結果
関数を二次関数で定義した場合
(3)PictureBoxに、三角関数のグラフを描画する例
・同様に三角関数も描画可能です。
''' <summary>
''' 関数(三角関数)
''' </summary>
''' <param name="x">入力</param>
''' <returns>出力</returns>
''' <remarks></remarks>
Public Function fnc1(ByVal x As IntegerAs Integer
    Return 50 * Math.Sin(x / 15)
End Function
[VB.NET]関数を三角関数で定義した場合
実行結果
関数を三角関数で定義した場合
(4)PictureBoxに、平方根の関数のグラフを描画する例
・平方根の関数も同様です。
''' <summary>
''' 関数(平方根)
''' </summary>
''' <param name="x">入力</param>
''' <returns>出力</returns>
''' <remarks></remarks>
Public Function fnc1(ByVal x As IntegerAs Integer
    Return 10 * Math.Sqrt(x)
End Function
[VB.NET]関数を平方根で定義した場合
実行結果
関数を平方根で定義した場合
nice!(0)  コメント(0)  トラックバック(0) 
共通テーマ:パソコン・インターネット

nice! 0

コメント 0

コメントを書く

お名前:[必須]
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。