2017. 6. 4.
石立 喬

Visual Studio Community 2017の使い方(6)

―― Canvasを使用して、1〜3次式をグラフで表示する ――

 レイアウトパネルの一つに、図形や画像、文字を描画するのに便利なCanvasがある。ここでは、理工系への応用の一つとして、関数のグラを描画する例を示す。具体的には、グラフ用紙の上に一次式、二次式、三次式を色を変えて描画する。これは、「Visual Studio 2012 Expressの易しい使い方(5)」のUWP版である。アンチエリアシング処理のため、垂直、水平方向の直線は太めに表示されることが分かった。

Win2Dのインストール(プロジェクト毎に必要なので、再度紹介する)
1)「ソリューションエクスプローラー」で、「ソリューション'App6'(1プロジェクト)」(プロジェクト名は一例)を右クリックする。この代わりに、メニューから、「ツール」→「NuGetパッケージマネージャー」→「ソリューションのNuGetパッケージの管理」でも良い。
2)現れたメニューから、「ソリューションのNuGetパッケージの管理」を選択する。
3)現れたウィンドウで、左上の「参照」タブを選択し、使用できるパッケージのリストを表示させる。
4)左上の検索欄に「win2d」と入力して検索し、「Win2d.uwp」を選択し、右側のチェックボックスにチェックを入れ、右下の「インストール」をクリックする。
5)「変更の確認」ウィンドウで、「OK」をクリックする。
5)「ライセンスの同意」ウィンドウが開くので、「同意する」をクリックする。

CanvasでWin2Dを使用するための準備(これについても、念のために簡単に再説明する)
1)「ソリューションエクスプローラー」で、「MainPage.xaml」をダブルクリックして、「XAML」エディタを表示させる。
2)XAMLコードのPageの最初の部分に、
    xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"
を追加する(図2参照)。
3)「表示」→「ツールボックス」で表示させた「ツールボックス」の「すべてのXAMLコントロール」欄から「Canvas」を持ってきて、「デザイン」画面上の適当な場所に仮に配置する。マウスで「Canvas」を持ってくると、適当なサイズのCanvasができる(図1および図2参照、この場合は、 Hight="100" Width="100"になった)。


図1 「デザイン」画面上の適当な位置に仮に配置したCanvas



図2 仮に配置したCanvasに対するXAMLコード


4)XAMLエディタ上で、「Canvas」を「canvas:CanvasControl」に書き換え、必要なサイズ、位置に設定変更する。
5)「XAML」エディタで「CanvasControl」を選択し、「プロパティ」ウィンドウで、名前を「canvas1」とし、Drawイベントの右の空欄をダブルクリックして、イベントハンドラーCanvasControl_Drawを生成する。
6)Pageを閉じるときのイベントハンドラーとして、「Unload="Page_Unloaded"」を追加設定して、Canvasの破棄に使用する。このため、「XAML」エディタで「Page」を選択して「プロパティ」ウィンドウを開き、イベントでUnloadを選んでダブルクリックする。図6に示すイベントハンドラーPage_Unloadのスケルトンも同時に生成される。
7)MainPage.xaml.cppに、
    using namespace Microsoft::Graphics::Canvas;
を追加する(図4参照)。

得られたXAMLコード
 最終的に作成したXAMLコードの内容を図3に示す。Canvasのサイズは、Height="400"、Width="400"に変更しており、場所も、左上に詰めて、Margin="0, 0, 0, 0"に変更してある。


図3 最終的なXAMLコード


DrawLineメソッド
 CanvasDrawingSessionクラスは、Canvas上にグラフィックを描画するメソッドを発するのに用いられる。DrawLineはそのメソッドの一つで、ここで使用する形式のものは、
  DrawText(
     float x0, ----------- 始点のX座標
     float y0, ----------- 始点のY座標
     float x1, ----------- 終点のX座標
     float y1, ----------- 終点のY座標
     Color color, -------- 線の色、Windows.UI.Color
    (float strokeWidth,) ---- 線の幅、ピクセル(デフォルトは1)、ただし、アンチエリアシングのため、奇数では太く見える
    (CanvasStrokeStyle strokeStyle,) ---- 線のスタイル、Solid、Dash、Dot、DashDot、DashDotDot(デフォルトはSolid)
  )
である。floatの代わりに、Vector2型(pointを指定)を用いることもできる。()はデフォルトで省略されることが多い。

グラフの描き方
 グラフは、DrawLineを使用し、
   DrawLine(xi-1, yi-1, xi, yi, color, width)
を繰り返す。ただし、x、yは座標値で、添え字のi-1は、一つ前の値を意味する。
 グラフの書き初めには、前の値が無いので、xi-1 = xi、yi-1 = yiとして、代入のみを行い、DrawLineは実行しない。yiがグラフの範囲から外れた場合にも同様とする。xの刻みを細かくすると、グラフがよりスムーズになり、グラフの範囲境界付近での不自然は無くなるが、演算時間がかかる。

プログラムの作成
 図4はプログラムの最初の部分で、Canvasのための名前空間と、Colors::Blackなど色のための名前空間を追加してある。図5は、CanvasクラスのInvalidateメソッドにより呼び出されるCanvasControl_Drawメソッドの内容を示したもので、三種類のグラフをCanvas上に描画する。
 まず最初に、DrawLineメソッドを用い、色をBlackとGrayで切り替えながら、グラフ用紙を作成する。一次式、二次式、三次式のグラフは、typeを示す変数iを変えながら関数Functionsを呼び出して描画する。
 色は、
   Color color[] = {Colors::Red, Colors::Blue, Cplors::Green};
によって配列化しておき(図5の中には表示されていないが・・・)、これで指定する。
 一次式、二次式、三次式は関数Functionsで定義し、第1引数で切り替える(図6参照)。


図4 プログラムの最初の部分で、名前空間の追加を行う



図5 CanVasControl_Drawメソッドで、グラフ用紙とグラフを描画する



図6 Canvasの書き換えと破棄のためのプログラム


 なお、念のために説明しておくと、ユーザー作成関数Functionsに関して、ヘッダーファイルMainPage.xaml.hに記述するのを忘れてはいけない。図7はエディタにMainPage.xaml.hを開いたところで、canvas1_DrawとPage_Unloadedは、別途自動的に宣言されている。


図7 ユーザー作成関数は、手作業で、MainPage.xaml.hに登録しておく必要がある


得られた結果
 得られた結果を図8に示す。方眼紙の線幅はデフォルト(1ピクセル)を使用したが、アンチエリアシングのために、薄めの色の2ピクセル分が使用され、やや薄くかつ太めに感じる。グラフの線幅は、当初デフォルトの値(1ピクセル)を用いたが、方眼紙に比べて細めに感じられたので、線幅を2に指定して、バランスをとった。xの刻みを0.02fとしたので、方眼紙の上下周辺部で、グラフの一部に、過不足が見られる。刻みを0.01fとすると改善されることを確認してある。方眼紙を含め、すべての線幅を1ピクセルにした場合の結果を参考までに図9に示す。方眼紙に用いた垂直、水平の直線は太めに、それ以外のグラフは、細く感じる。


図8 得られた結果



図9 すべての線幅を1ピクセルにした場合の結果、グラフが細く見える


直線の場合の線の引き方を調べてみた
 線幅の指定を1〜8にして、黒の垂直方向直線を描いたのが図10である。指定した線幅(ピクセル値)が偶数の場合にはそのままの太さで黒で線を引き、奇数の場合は、それより1だけ大きい偶数の線幅で両端をグレイにして線を引いている。したがって、指定した線幅が1の場合には、線幅が2のグレイの線が引かれる。これが、グラフ用紙の直線が太く見える原因である。線幅が常に偶数なので、指定ピクセル位置の右の本数(指定ピクセルを含む)と左の本数(指定ピクセルを含まない)を同じになっている。


図10 常に偶数ピクセル幅の線が描かれる


 斜めの直線について調べたのが図11で、水平・垂直の場合のように、線幅が偶数になる規則は見られず、特に、線幅指定が1の時の幅が太く感じられない。


図11 斜めの直線に対しては、指定した幅相応の直線が描かれる







「Visual C++の勉強部屋」(目次)