インターフェイスに対する透過プロキシ

前回の DLR で名前付き引数を使うでは、メソッドに引数として「キーと値のペア」を渡す方法を考え、
動的言語ランタイム (DLR) を利用する方法を紹介しました。
しかし、同じ処理を複数の場所で呼び出す必要があるなど、再利用性を重視する場合は、
なるべく静的にシグネチャを解決する方法がよいでしょう。

そこで今回は、呼び出すサービスをインターフェイスとして定義し、透過プロキシ (transparent proxy) を利用してみます。
先にコードを示します。

このコードでは、RealProxy クラスを継承した HttpProxy<IService> クラスを作成しています。
RealProxy はプロキシの実体となるものであり、
その外層である透過プロキシを RealProxy.GetTransparentProxy メソッドで取得できます。

一方、利用する側の Program.cs では、ICgisService インターフェイスを定義しておきます。
その透過プロキシを生成すれば、ICgisService インターフェイスを実装するクラスが存在しなくてもメソッドを呼び出すことができ、
実体は HttpProxy<IService> クラスの Invoke メソッドとなります。

また、BaseUriAttribute クラスを定義しており、
呼び出される Web API のベースとなる URI を属性で指定できるようにしています。

WCF における契約プログラミングでは、クライアント側とサーバー側で同一のインターフェイスを利用し、
クライアント側からのアクセスを上記のように透過プロキシで実装する方法があります。
方法 : ChannelFactory を使用する にある通り、ChannelFactory.CreateChannel メソッドで透過プロキシを生成します。

前回:DLR で名前付き引数を使う

作成したサンプル
TransparentHttpConsole (GitHub)

バージョン情報
C# 7.0
.NET Framework 4.5

参照
RealProxy クラス
方法 : ChannelFactory を使用する

カテゴリー: .NET Framework. タグ: . 1 Comment »

DLR で名前付き引数を使う

C# で、メソッドに引数として「キーと値のペア」を渡す方法を考えてみます。
例えば HTTP で GET でアクセスするときに URL でクエリ文字列を指定する場合が挙げられます。

よく使われているのは、メソッドの引数に Dictionary や匿名型オブジェクトを渡す方法かと思います。
以下の HttpHelper クラスのように実装します。
なお、WebClient クラスではクエリ文字列 (QueryString プロパティ) は NameValueCollection 型であるため、
受け取った情報を NameValueCollection 型に変換しています。

なお、ここでは題材として CGI’s 郵便番号検索 API を利用しています。

さて、動的言語ランタイム (DLR)名前付き引数を利用して、引数の情報を実行時に解決できないかと考えると、
次のような方法を思いつきます。

dynamic http = new DynamicHttpProxy();
var result = http.Get(Uri_Cgis_Xml, zn: "402", ver: 1);

実際、DynamicObject クラスを継承した DynamicHttpProxy クラスを次のように作れば可能です。

TryInvokeMember メソッドの中で、引数の名前は binder.CallInfo.ArgumentNames で取得できます。
ただし、引数の名前を指定せずに渡された分はここに含まれない (コレクションの長さが変わる) ため注意が必要です。

 

また、C# 7.0 で追加された ValueTuple を利用して、

var result = HttpHelper.Get(Uri_Cgis_Xml, (zn: "6050073"));

とする案もありましたが、

  • 要素が 1 つ以下の場合、タプル リテラルを記述できない
  • コンパイル後はフィールド名が残らないため、実行時に動的に取得できない

という制約により実現できませんでした。

次回:インターフェイスに対する透過プロキシ

作成したサンプル
DynamicHttpConsole (GitHub)

バージョン情報
C# 7.0
.NET Framework 4.5

参照
動的言語ランタイムの概要
名前付き引数と省略可能な引数
タプル – C# によるプログラミング入門

Leap Motion で手の回転状態を取得する

Leap Motion Controller の公式 SDK では、手の回転の状態をオイラー角で取得できるようになっています。
具体的には、Hand.Direction (Vector オブジェクト) の Yaw, Pitch, Roll プロパティが用意されています。
ただし、Hand クラスの説明を参照すると、 ロールについては Direction.Roll ではなく PalmNormal.Roll を使うように書かれています。

float pitch = hand.Direction.Pitch;
float yaw = hand.Direction.Yaw;
float roll = hand.PalmNormal.Roll;

しかし、これらの値を使って実装してみても、期待通りの動作にはなりません。

そこで、前回の 3D における回転の表現と相互変換の内容をもとに、手の回転の状態を取得する機能を自作しました。

Hand.Direction と Hand.PalmNormal はともに長さ 1 で直交しているため、
これらをそれぞれ (0, 0, -1) と (0, -1, 0) の回転後のベクトルと見なして、
前回作成した Rotation3DHelper クラスを利用してオイラー角を求めれば OK です。

全体のソースコードは HandRotationLeap (GitHub) にあります。
このサンプルでは、手とさいころの回転の状態を同期させています。

Hand Rotation by Leap Motion Controller

前回: 3D における回転の表現と相互変換

バージョン情報
.NET Framework 4.5
Leap Motion SDK 2.3.1

参照
Hand クラス

3D における回転の表現と相互変換

以前に投稿した WPF で 3D オブジェクトを回転させるではオブジェクトの回転の状態を行列で表していましたが、
3 次元空間における回転を表現する方法は、次のように何通りか考えられます。
なお、原点を中心に回転させるものとし、回転角度は、回転軸を表すベクトルの方向に右ねじを押し込む場合を正とします。

  1. 行列
    • 3 次正方行列。とくに、回転を表すものは直交行列であり、P^{-1} = {}^t P が成り立つ
    • WPF では Matrix3D 構造体
  2. 四元数 (クォータニオン)
  3. オイラー角 (ロール、ピッチ、ヨー)
    • 任意の回転を 3 回の単純な回転の合成により表す。詳細の定義はロール・ピッチ・ヨー ― Kinectで学ぶ数学を参照
    • 座標系ごと回転させる
    • ロール、ピッチ、ヨーをそれぞれどの軸に対応させるか、どの順番で作用させるかで結果が変わってしまうため注意が必要
  4. 特定の 2 点の回転前後の座標
    • とくに、直交する 2 つのベクトルを用いるとよい

3D のプログラミングをしていると、API によってどの表現を利用するかが異なることがあります。
以下では、これらの表現を互いに変換する方法について考えます。

■ 行列 → 2 点の座標

任意のベクトルに対して行列を作用させれば回転後のベクトルが求められます。
WPF では演算子 * が用意されています。

■ 四元数 → 行列

四元数の成分から行列の各成分を計算できます (詳細は四元数による回転行列の表現を参照)。
WPF では Matrix3D.Rotate メソッドとして用意されています。

■ オイラー角 → 行列または四元数

ここでは、ヨーは y 軸、ピッチは x 軸、ロールは z 軸のまわりの回転を表し、この順に適用されるとします。
(元の座標系における) ヨー、ピッチ、ロールを表す回転行列をそれぞれ R_y, R_p, R_r とし、それぞれの回転角度を \theta_y, \theta_p, \theta_r とします。
すなわち、

R_y = \left( \begin{array}{ccc} \cos \theta_y & 0 & \sin \theta_y \\ 0 & 1 & 0 \\ -\sin \theta_y & 0 & \cos \theta_y \end{array} \right), R_p = \left( \begin{array}{ccc} 1 & 0 & 0 \\ 0 & \cos \theta_p & -\sin \theta_p \\ 0 & \sin \theta_p & \cos \theta_p \end{array} \right), R_r = \left( \begin{array}{ccc} \cos \theta_r & -\sin \theta_r & 0 \\ \sin \theta_r & \cos \theta_r & 0 \\ 0 & 0 & 1 \end{array} \right)

このとき、座標系ごとヨー、ピッチ、ロールの順に適用した回転は、元の座標系で R_y R_p R_r で表されます (適用の順序が逆になる)。
証明は次のようにできますが、実際の回転をイメージするとわかりやすいと思います。

証明

ベクトル {\bf x} にヨーを作用させると、
R_y {\bf x}
次に、これにピッチを作用させるには、いったん座標系を戻して R_p を作用させるから、
R_y R_p R_y^{-1} \cdot R_y {\bf x} = R_y R_p {\bf x}
同様に、これにロールを作用させると、
(R_y R_p) R_r (R_y R_p)^{-1} \cdot R_y R_p {\bf x} = R_y R_p R_r {\bf x}
(証明終)

WPF での実際の演算では四元数を使うとよいでしょう。

■ 2 点の座標 → オイラー角

ここでは、2 点として {\bf e}_z = (0, 0, 1), {\bf e}_y = (0, 1, 0) を選びます。
これらの回転後のベクトルがそれぞれ {\bf u}, {\bf t} で与えられたとすると、オイラー角は以下の手続きにより求められます。

まず、{\bf u} の x 要素と z 要素の比はピッチおよびロールの影響を受けないから、
\tan \theta_y = \dfrac{{\bf u}_x}{{\bf u}_z}
により、\theta_y, R_y が決まる。

ピッチおよびロールの決め方から、
\tan \theta_p = \dfrac{- (R_p {\bf e}_z)_y}{(R_p {\bf e}_z)_z}, \tan \theta_r = \dfrac{- (R_r {\bf e}_y)_x}{(R_r {\bf e}_y)_y}

また、前項と同様に考えて、{\bf u} = R_y R_p {\bf e}_z, {\bf t} = R_y R_p R_r {\bf e}_y であるから、
R_p {\bf e}_z = R_y^{-1} {\bf u}, R_r {\bf e}_y = R_p^{-1} R_y^{-1} {\bf t}

したがって、\theta_p, \theta_r も順に決まる。
なお、この決め方の場合、回転角度の範囲は、
- \pi < \theta_y \le \pi, - \dfrac{\pi}{2} \le \theta_p \le \dfrac{\pi}{2}, - \pi < \theta_r \le \pi
となる。
(終)

arctan を求めるには、Math.Atan2 メソッドを使うとよいでしょう。

以上により、行列 → 2 点の座標 → オイラー角 → 四元数 → 行列と変換する方法が与えられたので、
回転の表現を相互に変換できるようになります。

では、これらを実装してみます。
ベクトル、行列、四元数を扱うための System.Numerics.Vectors という、WPF のライブラリよりも高機能なライブラリもあるのですが、
今回は WPF のライブラリのみを利用して実装したいと思います。

全体のソースコードは RotationTest (GitHub) にあります。
これらのメソッドを呼び出すテストが付いています。

前回: WPF で 3D オブジェクトを回転させる
次回: Leap Motion で手の回転状態を取得する

バージョン情報
.NET Framework 4.5

参照

WPF で 3D オブジェクトを回転させる

前回の WPF で 3D オブジェクトを表示するに引き続いて、今回は 3D オブジェクトを回転させます。
図のようにボタンを配置して、6 方向の回転ができるように実装します。

次のようにコードを追加・変更します。

ボタンとして RepeatButton を配置しています。
RepeatButton は、押したままにしておけば断続的に Click イベントが発生します。
また回転の状態を表すために、ModelVisual3D.Transform の中で MatrixTransform3D を使います。

回転には、回転軸と回転角度が必要です。

  • 回転軸は、ベクトルで表されます。
  • 回転角度は、回転軸の方向に右ねじを押し込む場合を正とします。

6 つのボタンはそれぞれ、x, y, z 軸を回転軸とした正方向または負方向の回転を表します。
1 回の Click イベントにつき 5° ずつ回転させています。
なお、カメラは z 軸上の正の位置から原点方向を見下ろし、右側が x 軸の正、上側が y 軸の正を表しています。

Click イベントハンドラーの中で、Matrix3D.Rotate メソッドを呼び出すことでオブジェクトを回転させます。
引数には、回転軸と回転角度を表す Quaternion (四元数) を指定します。
このように、回転軸と回転角度がわかっている場合は比較的簡単に実装ができます。

下図は、最初の状態から x 軸のまわりに -60° 回転させたところです。

全体のソースコードは DiceRotationWpf (GitHub) にあります。
マウスまたはタッチのドラッグ操作でも回転できるようになっています。

Dice Rotation

 

前回: WPF で 3D オブジェクトを表示する
次回: 3D における回転の表現と相互変換

作成したサンプル
DiceRotationWpf (GitHub)

バージョン情報
.NET Framework 4.5

参照
3-D グラフィックスの概要
3-D 変換の概要

WPF で 3D オブジェクトを表示する

WPF の 3D グラフィックスの機能を使って、3D オブジェクトを表示する方法を示します。
XAML でさいころのような立方体を描画することを目指します。

Dice (XAML)

先に XAML を示します。この後に簡単な説明が続きます。

 

まず、Viewport3D を配置します。
3D オブジェクトを描画するには次の 3 種類のものが必要で、これらを Viewport3D に設定します。

カメラ
Viewport3D.Camera プロパティに指定します。PerspectiveCamera を使うと、遠近感が出ます。
既定では LookDirection="0,0,-1" UpDirection="0,1,0" となっており、
つまり z 軸の逆方向を向いており、y 軸の正方向が上になっています。

照明
通常のオブジェクトと同様に、Viewport3D.Children プロパティにモデルとして追加します。
AmbientLight を使うと、影がなく、一様な明るさでオブジェクトが表示されます。

オブジェクト
主に ModelVisual3D として定義し、Viewport3D.Children プロパティに追加します。

以下では、ModelVisual3D の設定について書いていきます。
GeometryModel3D でオブジェクトを定義し、ModelVisual3D.Content プロパティにそれを指定します。
複数のオブジェクトをグループ化するには、Model3DGroup を使います。
GeometryModel3D には、マテリアルとジオメトリを指定します。

マテリアル

GeometryModel3D.Material プロパティで、何を表示するかを指定します。
ここでは、さいころの面を描くために 2D の TextBlock を用意しておき、それをテクスチャとして指定しています。
2D の Brush をテクスチャとして利用するには、DiffuseMaterial を使います。

また、BackMaterial プロパティに、Material プロパティと同じものを指定すれば、裏面には表面を反転したものが表示されます。
つまり、「3」の裏面は「ε」のようになります。

ジオメトリ

GeometryModel3D.Geometry プロパティで、どこに表示するかを指定します。
具体的には、MeshGeometry3D を利用して、次のものを指定します。

点の集合 (Positions プロパティ)
メッシュを構成する三角形に分割した場合に、頂点となる点の集合を指定します。

三角形の集合 (TriangleIndices プロパティ)
Positions プロパティで指定した点に0からインデックスを付けて、メッシュを構成する三角形の頂点を列挙します。
三角形の頂点の順番は、表側から見て反時計回りになるように指定します。

テクスチャの位置 (TextureCoordinates プロパティ)
Positions プロパティで指定した各点が、マテリアルの中のどの点に対応するかを指定します。
マテリアルは 2D なので、左上が (0, 0)、右下が (1, 1) です。

例えば、

<MeshGeometry3D Positions="-1,-1,1 1,-1,1 1,1,1 -1,1,1" TriangleIndices="0,1,2 0,2,3" TextureCoordinates="0,1 1,1 1,0 0,0"/>

とした場合は、P0(-1, -1, 1), P1(1, -1, 1), P2(1, 1, 1), P3(-1, 1, 1) の 4 点があり、
メッシュは P0P1P2 と P0P2P3 の 2 つの三角形で構成され、
P0 が左下、P1 が右下、P2 が右上、P3 が左上となるようにテクスチャを描画するという意味になります。
なお、これらの値を XAML 上で列挙するときの区切り文字としては、カンマまたはスペースの両方が使えます。

アフィン変換 (移動、スケール、回転など) について

3D オブジェクトのアフィン変換は、ModelVisual3D.Transform プロパティで指定します。

コードでの記述について

XAML の代わりに C# などの .NET のコードで記述することもできます。
同一の処理が繰り返される場合には、コードで生成したほうが簡単に表現できることもあります。

 

次回: WPF で 3D オブジェクトを回転させる

作成したサンプル
Wpf3DSample (GitHub): コードで描画した例もあります。

バージョン情報
.NET Framework 4.5

参照
3-D グラフィックスの概要
3-D 変換の概要

マウスのドラッグ イベントを Rx で実装する

WPF などの GUI アプリケーションでマウスのドラッグ操作を扱うには、
例えばマウスのドラッグ中の各点の情報も通知するなどの要件に合わせて、
基本的には自分で実装することになると思います。

従来であれば、MouseDown などの各イベントごとにイベントハンドラーを登録して実装していましたが、
リアクティブ プログラミングにすることで、より抽象度の高い形式で扱えるようになります。
今回は、WPF のマウスのドラッグ イベントを Reactive Extensions (Rx) で実装してみます。

WPF アプリケーション プロジェクトを作成して、NuGet で System.Reactive をインストールします。
そして次のクラスを作成します。

イベントと IObservable は、本質的には等価です。
まず Observable.FromEventPattern メソッドを使って、
MouseDown などの既存のイベントを IObservable<MouseEventArgs> に変換します。

ドラッグの実装方法については、
MouseDown が発生してから MouseUp または MouseLeave が発生するまでの間、MouseMove を通知させます。
これが MouseDown の発生のたびに開始するため、
MouseDrag の型は IObservable<IObservable<Vector>> のような入れ子になります。
ここでは、MouseDown イベントが発生した位置からの変位を通知することにしています。
(要件によって実装方法は異なるでしょう。)

次に、上で実装した MouseDrag を利用するには、次のコードのようになります (主にコンストラクターの部分)。
完全なソースコードは MouseRx2Wpf (GitHub) にあります。

ウィンドウには、変位とそれを表す 8 方向の矢印を表示しています。

MouseRx2Wpf

 

この方法はマウス以外にも応用できます。
Leap Image Pinch は、Leap Motion Controller を使って空中で 2 本の指でつまんで画像をドラッグする例です。

作成したサンプル
MouseRx2Wpf (GitHub)

バージョン情報
.NET Framework 4.5

参照
System.Reactive
Reactive Extensionsの概要と利用方法
Leap Image Pinch