2009年1月11日日曜日

[.NET]カスタマイズした構成情報の利用(.NET1.1以前が対象)

[はじめに]
(1)カスタム構成セクションとは?
  通常、アプリケーションの構成情報は、appSettingsノード配下の
  addノード(key属性とvalue属性)に記述するルールですが、
  独自のルール(独自のXMLタグ)で定義することもできます。
  この独自のXMLタグで定義された構成情報を、「カスタム構成セクション」と呼びます。
  「カスタム構成セクション」にアクセスする為には、
  プログラム上で「カスタム構成セクションハンドラ」クラスを実装し、
  構成ファイルに「カスタム構成セクションハンドラ」を追加する必要があります。
(2)カスタム構成セクションハンドラとは?
  カスタム構成セクションにアクセスする為には、
  その独自のXMLタグを解析する必要があります。
  その独自のXMLタグを解析するクラスを、「カスタム構成セクションハンドラ」と呼びます。
  カスタム構成セクションハンドラは、以下の(a)(b)の条件に従って実装する必要があります。
   (a)System.Configuration.IConfigurationSectionHandlerインタフェースを実装する。
   (b)IConfigurationSectionHandlerインタフェースのCreateメソッドに、
     カスタム構成セクションを解析する処理を実装する。
(3)カスタム構成セクションハンドラが、カスタム構成セクションにアクセスするには?
  カスタム構成セクションハンドラがカスタムセクションにアクセスする為には、
  構成ファイルに、構成セクションハンドラを追加する必要があります。
  追加することにより、カスタム構成セクションハンドラとカスタムセクションの対応付けを
  定義したことになります。
(4)利用可能な.NET Frameworkのバージョンは?
  本記事のサンプルは、.NET1.1以前で主流だった方法です。
  .NET2.0以降では、「ConfigurationSection」クラスを使用する方法が
  推奨されています。(.NET2.0以降でも使用可能)
(5))参考文献
  ・『MSDN Library for VisualStudio2008日本語版』
  ・『MCTSスキルチェック問題集70-536 .NET Framework2.0アプリケーション構築基礎』

カスタム構成セクションにアクセスする例を、以下の(1)~(4)に分けて示します。

(1)カスタム構成セクションの定義
  例として、日本の地域と県、県と県庁所在地の対応を定義しています。
[ソース]
<configuration>
  <myCustomGroup>
    <Country Name="Japan">
      <Area Name="Kanto">
        <Prefecture Name="Tokyo" MajorCity="Tokyo"/>
        <Prefecture Name="Kanagawa" MajorCity="Yokohama"/>
        <Prefecture Name="Ibaragi" MajorCity="Mito"/>
      </Area>
      <Area Name="Chubu">
        <Prefecture Name="Aichi" MajorCity="Nagoya"/>
        <Prefecture Name="Gifu" MajorCity="Gifu"/>
        <Prefecture Name="Mie" MajorCity="Tsu"/>
      </Area>
    </Country>
  </myCustomGroup>
        (以下省略)
          :
例:カスタム構成セクションの定義

(2)カスタム構成セクションハンドラの実装   System.Configuration.IConfigurationSectionHandlerインタフェースを   実装したクラスを定義します。   System.Configuration.IConfigurationSectionHandlerインタフェースの   Createメソッドに、カスタム構成セクションのアクセス処理を実装します。   この例では、カスタム構成セクションから、県と県庁所在地の一覧を取得し、   HashTableに格納しています。 [ソース]
''' <summary>
''' カスタム構成セクションハンドラ
''' ※.NET1.1以前で使用可能。
'''  .NET2.0以降ではSystem.Configuration.ConfigurationSectionクラスを推奨
''' </summary>
''' <remarks></remarks>
Public Class MyCustomConfigHandler1_1
    Implements System.Configuration.IConfigurationSectionHandler

    ''' <summary>
    ''' 構成セクションハンドラを作成する。
    ''' </summary>
    ''' <param name="parent">親オブジェクト</param>
    ''' <param name="configContext">構成コンテキストオブジェクト</param>
    ''' <param name="section">セクションXMLノード</param>
    ''' <returns>作成されたセクションハンドラオブジェクト</returns>
    ''' <remarks></remarks>
    Public Function Create( _
        ByVal parent As Object, _
        ByVal configContext As Object, _
        ByVal section As System.Xml.XmlNode) As Object _
        Implements _
        System.Configuration.IConfigurationSectionHandler.Create

        Dim configTable As New Hashtable()

        For Each areaNode As XmlNode In section.ChildNodes
            For Each prefNode As XmlNode In areaNode.ChildNodes
                configTable.Add( _
                    prefNode.Attributes("Name").Value, _
                    prefNode.Attributes("MajorCity").Value)
            Next
        Next

        Return configTable

    End Function
End Class
[VB.NET]例:カスタム構成セクションハンドラの実装

(3)構成ファイルにカスタム構成セクションハンドラの追加   「myCustomGroup」、「Country」の対応付けを定義し、   更に「Country」のセクションハンドラを定義しています。   type属性には、カスタム構成セクションハンドラのアセンブリ修飾名を指定します。   アセンブリ修飾名については、   MessageBox.Show( _    New MyCustomConfigHandler1_1().GetType().AssemblyQualifiedName)   で確認できます。 [ソース]
<configuration>
  <configSections>
    <sectionGroup name="myCustomGroup" >
      <section 
        name="Country" 
        type="CustomConfig.MyCustomConfigHandler1_1, 
              CustomConfig, 
              Version=1.0.0.0, 
              Culture=neutral, 
              PublicKeyToken=null"/>
    </sectionGroup>
  </configSections>
        (以下省略)
          :
例:カスタム構成セクションハンドラの追加

(4)構成情報の取得   以下に、カスタム構成セクションハンドラを使用して構成情報を取得する例を示します。   取得には、System.Configuration.ConfigurationSettingsクラスの   GetConfigメソッドを使用します。(※.NET2.0以降では警告がでます。)   GetConfigの引数には、起点となるカスタム構成セクションのノード名を指定します。 [ソース]
Private Sub Button1_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Button1.Click

    Dim rtn As Object = Nothing
    Dim configTable As Hashtable = Nothing

    '「myCustomGroup/Country」のXMLノードを起点とし、
    '構成情報を取得する。
    rtn = System.Configuration.ConfigurationSettings.GetConfig( _
        "myCustomGroup/Country")
    configTable = CType(rtn, Hashtable)

    '取得した構成情報をメッセージボックスに表示
    Dim sb As New StringBuilder()
    For Each k As String In configTable.Keys
        sb.Append(k & ":" & configTable(k).ToString() & vbCrLf)
    Next
    MessageBox.Show(sb.ToString())

End Sub
[VB.NET]例:カスタム構成セクションハンドラを使用して構成情報を取得する

2009年1月1日木曜日

[Algo]組合せの数(nCm)の算出

[はじめに]
・n個の中からm個を選ぶ組合せの数(nm)を算出するプログラムです。
 例:a、b、cの3個の中から2個を選ぶ組合せは、
   ab、ac、bcの3通りであり、その数を数学的表記で『32』と表現します。
 .NETのクラスライブラリには算出するメソッドがないようなので作ってみました。
nmを算出する公式はいくつかありますが、
 代表的な公式と各々の特徴について、以下にまとめます。
・参考文献
 『Javaによるはじめてのアルゴリズム入門』

以下に、算出方法に対するプログラム例を示します。

(1)階乗による算出
 公式nm=n!/{m!×(n-m)!}
/// <summary>
/// 異なるn個のものからm個を選ぶ
/// 組み合わせの総数 nCmを取得する。
/// </summary>
/// <param name="n">n</param>
/// <param name="m">m</param>
/// <returns>nCm</returns>
public static decimal CalcComb01(decimal n, decimal m)
{
    //nCm = nCm-1 ×(n-m+1)/ m 
    return CalcFact(n) / (CalcFact(m) * CalcFact(n - m));
}

/// <summary>
/// 階乗を計算する。
/// </summary>
/// <param name="n">n</param>
/// <returns>nの階乗(n!)</returns>
public static decimal CalcFact(decimal n)
{
    if (n <= 0m) {
        return 1m;
    }
        
    return n * CalcFact(n - 1);
}
[C#][階乗による算出]
異なるn個のものからm個を選ぶ組み合わせの総数nmを取得する。

(2)漸化式による算出
 一般的に、漸化式の計算は再帰処理で実装できます。
 公式
 (i)m=0の場合
  nm=1
 (ii)m>0の場合
  nmnm-1×(n-m+1)/m
/// <summary>
/// 異なるn個のものからm個を選ぶ
/// 組み合わせの総数 nCmを取得する。
/// </summary>
/// <param name="n">n</param>
/// <param name="m">m</param>
/// <returns>nCm</returns>
public static decimal CalcComb02(decimal n, decimal m)
{
    //以下の漸化式に従って、再帰により算出する。

    //(1)m=0の場合、
    //      nCm = 1
    if (m == 0)
    {
        return 1;
    }

    //(2)m≠0の場合、
    //      nCm = nCm-1 ×(n-m+1)/ m 
    return CalcComb02(n, m - 1) * (n - m + 1) / m;

}
[C#][漸化式による算出]
異なるn個のものからm個を選ぶ組み合わせの総数nmを取得する。

(3)Π(パイ)による算出
 「(2)漸化式による算出」の公式は、
 総乗(掛け算を集約したもの)と解釈できるので、
 以下の公式でも表現できます。
 公式nm=Π{(n-k+1)/k} (※1≦k≦M)
/// <summary>
/// 異なるn個のものからm個を選ぶ
/// 組み合わせの総数 nCmを取得する。
/// </summary>
/// <param name="n">n</param>
/// <param name="m">m</param>
/// <returns>nCm</returns>
public static decimal CalcComb03(decimal n, decimal m)
{
    //組合せ(nCm)を、
    //以下の公式に従って、ループにより算出する。
    //         m
    // nCm = Π {(n-k+1)/ k }
    //         k=1

    decimal product = 1;

    for(decimal k = 1 ; k <= m ; k++)
    {
        product = product * (n - k + 1) / k;
    }

    return product;

}
[C#][Π(パイ)による算出]
異なるn個のものからm個を選ぶ組み合わせの総数nmを取得する。

2008年12月29日月曜日

[.NET]メールの送信(.NET2.0以降)

[はじめに]
メールを送信するサンプルプログラムです。(最も簡単な例)
クラスライブラリ
 .NETFramework2.0から新たに追加されたクラスを使用しています。
 (1.1以前では『System.Web.Mail』名前空間のクラスが使用されていましたが、
  2.0以降は『System.Net.Mail』名前空間のクラスが推奨されています。)







クラス名/列挙体名概要
System.Net.Mail.SmtpClientクラスSMTPサーバを表すクラスです。
System.Net.Mail.MailMessageクラスメールを表すクラスです。
System.Net.Mail.MailAddressクラスメールアドレスを表すクラスです。
System.Net.Mail.Attachmentクラス添付ファイルを表すクラスです。
System.Net.NetworkCredential認証情報を表すクラスです。
System.Net.Mail.MailPriority列挙体メールの優先度を表す列挙体です。

CDO(Microsoft Collaboration Data Objects)
 Windowsでは、メールの送信機能として『CDO』を用意しています。
 CDOは、VB6やEXCEL VBA等からも利用することができますが、
 インタフェースがわかりにくいものでした。
 .NETでは、CDOの呼び出しをカプセル化することで、
 よりわかりやすいインタフェースを提供しています。
・参考文献
 『MSDN Library for VisualStudio2008日本語版』
 
以下にサンプルソースを示します
''' <summary>
''' メールを送信する
''' </summary>
''' <param name="argSmtpServer">SMTPサーバ名</param>
''' <param name="argPortNo">ポート番号</param>
''' <param name="argSmtpAuth">SMTP認証の有無</param>
''' <param name="argUserName">認証ユーザ</param>
''' <param name="argPassword">認証パスワード</param>
''' <param name="argEnableSsl">SSLの使用有無</param>
''' <param name="argTimeout">タイムアウト(ミリ秒)(Nothingで100000)</param>
''' <param name="argFrom">メールアドレス(From)</param>
''' <param name="argTo">メールアドレス(To)</param>
''' <param name="argCc">メールアドレス(Cc)</param>
''' <param name="argBcc">メールアドレス(Bcc)</param>
''' <param name="argPriority">優先度</param>
''' <param name="argSubject">件名</param>
''' <param name="argBody">本文</param>
''' <param name="argIsHtml">HTMLかどうか</param>
''' <param name="argFile">添付ファイル</param>
''' <param name="argSubEnc">エンコード(件名)</param>
''' <param name="argBodyEnc">エンコード(本文)</param>
''' <remarks></remarks>
Private Sub SendMail( _
    ByVal argSmtpServer As String, _
    ByVal argPortNo As Integer, _
    ByVal argSmtpAuth As Boolean, _
    ByVal argUserName As String, _
    ByVal argPassword As String, _
    ByVal argEnableSsl As Boolean, _
    ByVal argTimeout As Integer?, _
    ByVal argFrom As String, _
    ByVal argTo() As String, _
    ByVal argCc() As String, _
    ByVal argBcc() As String, _
    ByVal argPriority As System.Net.Mail.MailPriority, _
    ByVal argSubject As String, _
    ByVal argBody As String, _
    ByVal argIsHtml As Boolean, _
    ByVal argFile() As System.IO.FileInfo, _
    ByVal argSubEnc As String, _
    ByVal argBodyEnc As String _
    )
    'SMTPサーバを設定
    '※サーバ名、ポート番号を設定
    Dim sClient As New System.Net.Mail.SmtpClient( _
        argSmtpServer, argPortNo _
    )

    'SMTP認証の設定
    If argSmtpAuth Then
        '認証が必要な場合は、ユーザ名とパスワードを設定
        sClient.Credentials = New System.Net.NetworkCredential( _
            argUserName, argPassword _
        )
    End If

    'SSLの使用有無を設定
    sClient.EnableSsl = argEnableSsl

    'タイムアウトを設定
    If argTimeout.HasValue Then
        sClient.Timeout = argTimeout
    End If

    'メールの設定
    Dim mail As New System.Net.Mail.MailMessage
    Try
        'メールアドレス(From)
        mail.From = New System.Net.Mail.MailAddress(argFrom)
        '※メールアドレス(To)を設定
        If Not (argTo Is NothingThen
            For Each addr As String In argTo
                mail.To.Add(addr)
            Next
        End If
        'メールアドレス(Cc)
        If Not (argCc Is NothingThen
            For Each addr As String In argCc
                mail.CC.Add(addr)
            Next
        End If
        'メールアドレス(Bcc)
        If Not (argBcc Is NothingThen
            For Each addr As String In argBcc
                mail.Bcc.Add(addr)
            Next
        End If

        '優先度
        '   高い:System.Net.Mail.MailPriority.High
        '   普通:System.Net.Mail.MailPriority.Normal
        '   低い:System.Net.Mail.MailPriority.Low
        mail.Priority = argPriority
        '件名を設定
        mail.Subject = argSubject
        '本文を設定
        mail.Body = argBody
        '本文をHTML形式にするかどうか
        mail.IsBodyHtml = argIsHtml
        '添付ファイル
        If Not (argFile Is NothingThen
            For Each f As FileInfo In argFile
                mail.Attachments.Add( _
                    New System.Net.Mail.Attachment(f.FullName))
            Next
        End If
        'エンコード(件名)
        '例:shift_jis、iso-2022-jp
        mail.SubjectEncoding = Encoding.GetEncoding(argSubEnc)
        'エンコード(本文)
        mail.BodyEncoding = Encoding.GetEncoding(argBodyEnc)

        'メールを送信
        sClient.Send(mail)
    Finally
        mail.Dispose()
    End Try
End Sub
[VB.NET]メールを送信するサンプル

/// <summary>
/// メールを送信する
/// </summary>
/// <param name="argSmtpServer">SMTPサーバ名</param>
/// <param name="argPortNo">ポート番号</param>
/// <param name="argSmtpAuth">SMTP認証の有無</param>
/// <param name="argUserName">認証ユーザ</param>
/// <param name="argPassword">認証パスワード</param>
/// <param name="argEnableSsl">SSLの使用有無</param>
/// <param name="argTimeout">タイムアウト(ミリ秒)(nullで100000)</param>
/// <param name="argFrom">メールアドレス(From)</param>
/// <param name="argTo">メールアドレス(To)</param>
/// <param name="argCc">メールアドレス(Cc)</param>
/// <param name="argBcc">メールアドレス(Bcc)</param>
/// <param name="argPriority">優先度</param>
/// <param name="argSubject">件名</param>
/// <param name="argBody">本文</param>
/// <param name="argIsHtml">HTMLかどうか</param>
/// <param name="argFile">添付ファイル</param>
/// <param name="argSubEnc">エンコード(件名)</param>
/// <param name="argBodyEnc">エンコード(本文)</param>
/// <remarks></remarks>
private void SendMail(
    string argSmtpServer, int argPortNo, bool argSmtpAuth, 
    string argUserName, string argPassword, bool argEnableSsl, 
    int? argTimeout, string argFrom, 
    string[] argTo, string[] argCc, string[] argBcc, 
    System.Net.Mail.MailPriority argPriority, 
    string argSubject, string argBody, bool argIsHtml, 
    System.IO.FileInfo[] argFile, 
    string argSubEnc, string argBodyEnc)
{
    //SMTPサーバを設定
    //※サーバ名、ポート番号を設定
    System.Net.Mail.SmtpClient sClient = 
        new System.Net.Mail.SmtpClient(argSmtpServer, argPortNo);
    
    //SMTP認証の設定
    if (argSmtpAuth) {
        //認証が必要な場合は、ユーザ名とパスワードを設定
        sClient.Credentials = 
            new System.Net.NetworkCredential(
                argUserName, argPassword);
    }
    
    //SSLの使用有無を設定
    sClient.EnableSsl = argEnableSsl;
    
    //タイムアウトを設定
    if (argTimeout.HasValue) {
        sClient.Timeout = argTimeout;
    }
    
    //メールの設定
    System.Net.Mail.MailMessage mail = 
        new System.Net.Mail.MailMessage();
    try {
        //メールアドレス(From)
        mail.From = new System.Net.Mail.MailAddress(argFrom);
        //※メールアドレス(To)を設定
        if (argTo != null) {
            foreach (string addr in argTo) {
                mail.To.Add(addr);
            }
        }
        //メールアドレス(Cc)
        if (argCc != null) {
            foreach (string addr in argCc) {
                mail.CC.Add(addr);
            }
        }
        //メールアドレス(Bcc)
        if (argBcc != null) {
            foreach (string addr in argBcc) {
                mail.Bcc.Add(addr);
            }
        }
        
        //優先度
        // 高い:System.Net.Mail.MailPriority.High
        // 普通:System.Net.Mail.MailPriority.Normal
        // 低い:System.Net.Mail.MailPriority.Low
        mail.Priority = argPriority;
        //件名を設定
        mail.Subject = argSubject;
        //本文を設定
        mail.Body = argBody;
        //本文をHTML形式にするかどうか
        mail.IsBodyHtml = argIsHtml;
        //添付ファイル
        if (argFile != null) {
            foreach (FileInfo f in argFile) {
                mail.Attachments.Add(
                    new System.Net.Mail.Attachment(f.FullName));
            }
        }
        //エンコード(件名)
        //例:shift_jis、iso-2022-jp
        mail.SubjectEncoding = Encoding.GetEncoding(argSubEnc);
        //エンコード(本文)
        mail.BodyEncoding = Encoding.GetEncoding(argBodyEnc);
        
        //メールを送信
        sClient.Send(mail);
    }
    finally {
        mail.Dispose();
    }
}
[C#]メールを送信するサンプル
補足
本サンプルは、送信元メールアドレスをYahooメールで確認しています。(2008.12.29現在)
Yahooメールで確認するには、
『Yahooメールを他のメーラーで送受信できるようにする』必要があります。
Yahooメールの『POPアクセスとメール転送』で、『ブラウザアクセスとPOPアクセス』に設定して下さい。
あとは、
ユーザ名:YahooID
パスワード:YahooIDのパスワード
SMTPサーバ:『smtp.mail.yahoo.co.jp』
SMTPのポート番号:『587』
でメールを送信できます。

2008年12月21日日曜日

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

[はじめに]
・関数(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]関数を平方根で定義した場合
実行結果 関数を平方根で定義した場合

2008年12月20日土曜日

[Algo]和と積から元の2数の算出

[はじめに]
(1)ある2数の和と積から、元の2数を求めるアルゴリズムです。
   例えば、『足して5』、『掛けて6』になる2つの数は、
   になります。
   これを解くアルゴリズムとして、
   2次方程式の解の解法を利用することができます。

   具体的には、
   Xについての2次方程式
   2-5X+6=0 は因数分解すると、
   (X-2)(X-3)=0 となり、
   解はX=2、3 となります。

   つまり、
   2-(α+β)X+αβ=0 の解が、
   X=α、β となることを利用することで、
   元の2数を求めることができます。

   α+β=Aαβ=Bとした時、
   2次方程式の解の公式から、
   2-AX+B=0 
   X= {A±(A2 - 4B)1/2} / 2 となり、 
   求める2数は、
   X= {A+(A2 - 4B)1/2} / 2 と
   X= {A-(A2 - 4B)1/2} / 2
   となります。

   また、2次方程式の判別式が負数の場合、
   つまり2次方程式の実数解が存在しない場合は、
   元の2数が存在しないので、解を算出する前にチェックする必要があります。

[参考]2次方程式の解の公式
2次方程式の解の公式
[ソース]
''' <summary>
''' 和(α+β)と積(α×β)から、αとβを算出する。
''' </summary>
''' <param name="sum">和(α+β)</param>
''' <param name="product">積(α×β)</param>
''' <returns>αとβ(存在しない場合はNothing)</returns>
''' <remarks></remarks>
Public Shared Function CalcValueBySumProduct(ByVal sum As IntegerByVal product As IntegerAs Decimal()
    'α、βの算出に
    '2次方程式の解の公式を利用する。
    '   以下の2次方程式を解くと、X=α、βになることを利用して、
    '   X*X - (α+β)*X + α*β = 0
    '   を解く。
    '   X= [(α+β)±√{(α+β)*(α+β) - 4*α*β}] / 2
    '補足
    '   実数解が存在しない場合は、解が存在しないものとする。
    Dim dist As Decimal = sum * sum - 4 * product

    If dist < 0 Then
        Return Nothing
    End If

    Dim sqrtDist As Decimal = Math.Sqrt(dist)
    Dim rtnValue() As Decimal = New Decimal(1) {}
    rtnValue(0) = (sum - sqrtDist) / 2
    rtnValue(1) = (sum + sqrtDist) / 2

    Return rtnValue
End Function
[VB.NET]和と積から元の2数を算出する。

[.NET]Imageの分割

ファイルから取り込んだImageを複数に分割する機会があったので、
作ってみました。

[ポイント]
(1)Imageオブジェクトを指定した個数で分割します。
   例:縦5個、横10個と指定すると、5×10の2次元配列でImageを作成します。
(2)Imageを分割するには、
   Graphics.DrawImage(Image, Integer, Integer, Rectangle, GraphicsUnit)
   を使います。
(3)参考文献
   『MSDN Library for VisualStudio2008日本語版』

[ソース]
''' <summary>
''' 指定したImageを分割する。
''' </summary>
''' <param name="originalImage">オリジナルImage</param>
''' <param name="verticalNum">分割数(垂直)</param>
''' <param name="horizontalNum">分割数(水平)</param>
''' <returns>分割済Image</returns>
''' <remarks></remarks>
Public Shared Function DivideImage( _
    ByVal originalImage As Image, _
    ByVal verticalNum As IntegerByVal horizontalNum As Integer _
    ) As Image()()

    '引数チェック
    If originalImage Is Nothing Then
        Throw New ArgumentNullException("originalImage is null")
    End If

    If verticalNum < 1 Then
        Throw New ArgumentOutOfRangeException("verticalNum < 1")
    End If

    If horizontalNum < 1 Then
        Throw New ArgumentOutOfRangeException("horizontalNum < 1")
    End If

    Dim g As Graphics = Nothing

    Dim rtnImage()() As Image = New Image(verticalNum - 1)() {}
    For i As Integer = 0 To verticalNum - 1
        rtnImage(i) = New Image(horizontalNum - 1) {}
    Next

    Dim originalSize As Size = originalImage.Size
    Dim divWidth As Integer = originalSize.Width / horizontalNum
    Dim divHeight As Integer = originalSize.Height / verticalNum

    For vCnt As Integer = 0 To verticalNum - 1
        For hCnt As Integer = 0 To horizontalNum - 1
            Try
                '空のImageを作成
                rtnImage(vCnt)(hCnt) = New Bitmap(divWidth, divHeight)
                'Imageを描画する為のGraphicsオブジェクトを作成
                g = System.Drawing.Graphics.FromImage( _
                       rtnImage(vCnt)(hCnt))
                'オリジナルImageから描画対象の領域を算出
                '[補足]
                '   領域の開始座標を
                '   ・hCnt * divWidth
                '   ・vCnt * divHeight
                '   ではなく、
                '   ・hCnt * originalSize.Width / horizontalNum
                '   ・vCnt * originalSize.Height / verticalNum
                '   にしているのは、誤差を軽減する為です。
                Dim rect As New Rectangle( _
                    hCnt * originalSize.Width / horizontalNum, _
                    vCnt * originalSize.Height / verticalNum, _
                    divWidth, _
                    divHeight _
                    )
                'オリジナルImageの内容を描画
                g.DrawImage( _
                     originalImage, 0, 0, rect, GraphicsUnit.Pixel)
            Finally
                If Not (g Is NothingThen
                    'Graphicsオブジェクトを解放
                    g.Dispose()
                End If
            End Try
        Next
    Next

    Return rtnImage
End Function
[VB.NET]Imageを分割する例

/// <summary>
/// 指定したImageを分割する。
/// </summary>
/// <param name="originalImage">オリジナルImage</param>
/// <param name="verticalNum">分割数(垂直)</param>
/// <param name="horizontalNum">分割数(水平)</param>
/// <returns>分割済Image</returns>
/// <remarks></remarks>
public static Image[][] DivideImage(
    Image originalImage, int verticalNum, int horizontalNum)
{
    
    //引数チェック
    if (originalImage == null) {
        throw new ArgumentNullException("originalImage is null");
    }
    
    if (verticalNum < 1) {
        throw new ArgumentOutOfRangeException("verticalNum < 1");
    }
    
    if (horizontalNum < 1) {
        throw new ArgumentOutOfRangeException("horizontalNum < 1");
    }
    
    Graphics g = null;
    
    Image[][] rtnImage = new Image[verticalNum][];
    for (int i = 0; i <= verticalNum - 1; i++) {
        rtnImage(i) = new Image[horizontalNum];
    }
    
    Size originalSize = originalImage.Size;
    int divWidth = originalSize.Width / horizontalNum;
    int divHeight = originalSize.Height / verticalNum;
    
    for (int vCnt = 0; vCnt < verticalNum ; vCnt++) {
        for (int hCnt = 0; hCnt < horizontalNum ; hCnt++) {
            try {
                //空のImageを作成
                rtnImage(vCnt)(hCnt) = new Bitmap(divWidth, divHeight);
                //Imageを描画する為のGraphicsオブジェクトを作成
                g = System.Drawing.Graphics.FromImage(
                    rtnImage(vCnt)(hCnt));
                //オリジナルImageから描画対象の領域を算出
                //[補足]
                // 領域の開始座標を
                // ・hCnt * divWidth
                // ・vCnt * divHeight
                // ではなく、
                // ・hCnt * originalSize.Width / horizontalNum
                // ・vCnt * originalSize.Height / verticalNum
                // にしているのは、誤差を軽減する為です。
                Rectangle rect = new Rectangle(
                     hCnt * originalSize.Width / horizontalNum, 
                     vCnt * originalSize.Height / verticalNum, 
                     divWidth, divHeight);
                //オリジナルImageの内容を描画
                g.DrawImage(
                    originalImage, 0, 0, 
                    rect, GraphicsUnit.Pixel);
            }
            finally {
                if (g != null) {
                    //Graphicsオブジェクトを解放
                    g.Dispose();
                }
            }
        }
    }
    
    return rtnImage;
}
[C#]Imageを分割する例

2008年1月1日火曜日

商品紹介メモ

いままで私が購入した商品です。
使い勝手が良かったものを備忘録として載せておきます。
(併せて関連商品も載せておきます。)

書籍
フリーソフト ベストガイド (100%ムックシリーズ)

TVゲーム
東北大学未来科学技術共同研究センター 川島隆太教授監修 脳を鍛える大人のDSトレーニング
東北大学未来科学技術共同研究センター 川島隆太教授監修 もっと脳を鍛える大人のDSトレーニング
英語が苦手な大人のDSトレーニング えいご漬け
英語が苦手な大人のDSトレーニング もっとえいご漬け
GOD EATER BURST(アドペント版) 特典 アペンド版:「プレミアムキャラクターダウンロードカード」付き
ファイナルファンタジーXIV

PCソフト
Microsoft Office Professional Academic 2010
Microsoft Office Professional 2010

家電・カメラ
EPSON インクカートリッジ(6色セット) IC6CL50
EPSON インクカートリッジ ICM50 マゼンダ

パソコン・オフィス用品
SANWA SUPPLY iPod・iPhone用USBケーブル(ホワイト) 12.5cm KB-IPUSBW
アイ・オー・データ機器 USB 2.0/1.1対応 ポータブルハードディスク 「カクうす」 ピアノブラック 320GB HDPC-U320K
I-O DATA USB 2.0/1.1対応 ポータブルハードディスク ピアノブラック 640GB HDPC-U640K
I-O DATA USB 2.0/1.1対応 ポータブルハードディスク ビターブラウン 640GB HDPC-U640BR

ホーム&キッチン
Panasonic スリムパルック蛍光灯 34形 丸形 クール色 FHC34ECW
HITACHI 紙パック式かるパック CV-PR20-P
HITACHI 紙パック式かるパック CV-PR10-A
HITACHI 紙パック式かるパック CV-PR20-N
HITACHI 紙パック式かるパック CV-PR200-N
HITACHI 紙パック式かるパック CV-PR200-R
HITACHI 紙パック式かるパック CV-PR10-R
SHARP POWERCYCLONE サイクロンクリーナー タービンヘッド シルバー系 EC-CT11-S
YAMAZEN ブラックメタルハンガーBH-WS ブラック

時計
[アレサンドラオーラ]Alessandra Olla 腕時計 1Pダイヤモンド入りバングルウォッチ シェル文字盤 シルバーステンレスベルト AO-7650-1 ホワイト

ヘルス&ビューティ
アイナソープ400 100g
☆「アイナソープ400 100g」★
セルフタンニングローション ブロンズマジック
セルフタンニングローション ブロンズマジック

CD
DISSIDIA 012【duodecim】FINAL FANTASY オリジナル・サウンドトラック(初回生産限定盤)(DVD付)
ファンタシースターポータブル2 オリジナルサウンドトラック「ウイングス オブ ユニバース」

[雑記]ドローン(DJI Mini 3)

(1)雑記 もともと多趣味の友人 masakazu Drone 氏が、 最近、 ドローン にハマり始めて、 更に、新たな趣味が増えたとのこと。 ドローン を始めてから、 まだ1年も経っていないとのことですが、 旅行先で山や川の景色を 空撮 して、 Youtube ...