旅行好きなソフトエンジニアの備忘録

プログラミングや技術関連のメモを始めました

【WPF】 拡大した画像上でクリックした座標の取得

今回やりたいことは文章だと説明が難しいのですが、下図の青丸部分をクリックするとクリックした箇所の座標は(x, y)=(75, 60)になります。 f:id:ni4muraano:20171021172729p:plain 次に上図のオレンジで囲った箇所を以前ブログに書いた方法で拡大表示して下図が得られたとします(【WPF】 Imageを拡大/平行移動させる - 旅行好きなソフトエンジニアの備忘録)。 f:id:ni4muraano:20171021172407p:plain
この時上図の青丸をクリックすると(x, y)=(50, 40)が得られます。ただ、拡大表示する前の座標は(75, 60)なので、拡大表示した状態で青丸をクリックしても(75, 60)という座標が欲しい、というのが今回やりたいことになります。

幸い以前ブログに書いた方法で拡大表示していたとすると、拡大表示するために利用した行列を参照できるので、この行列を利用すればやりたいことは実現できます。画像を表示するために使ったImageの名前をImage1にしたとすると、行列は以下の手順で取得できます。

// 拡大表示のために利用した行列を取得
var matrix = Image1.RenderTransform.Value;

この行列にはプロパティとしてM11, M12, M21, M22, OffsetX, OffsetYがありますが、これらは以下に対応しています。 \begin{pmatrix} M11 & M12 & OffsetX \\ M21 & M22 & OffsetY \\ 0 & 0 & 1 \end{pmatrix} 実際にはM12, M21には0が入るので、上記は更に簡単になります。 \begin{pmatrix} M11 & 0 & OffsetX \\ 0 & M22 & OffsetY \\ 0 & 0 & 1 \end{pmatrix} そして、この行列の逆行列を求めて拡大表示状態でクリックして得た座標に対して適用すると、拡大前の座標に戻すことができます。上記行列の逆行列は公式(2x2行列と3x3行列と4x4行列の逆行列の公式)から簡単に求めることができます。逆行列を以下のように定義すると、求める座標は以下から計算できます。

\begin{pmatrix} A11 & A12 & A13 \\ A21 & A22 & A23 \\ A31 & A32 & A33 \end{pmatrix}

DET=M11×M22
A11=M22÷DET
A12=0
A13=OffsetX×M22×(-1)÷DET
A21=0
A22=M11÷DET
A23=M11×OffsetY×(-1)÷DET

x=A11×x^{'} + A13
y=A22×y^{'} + A23

---2017年10月25日追記---
逆行列は自分で計算しなくてもInvertメソッドで取得可能でした。

// 拡大表示のために利用した行列を取得
var matrix = Image1.RenderTransform.Value;
// 逆行列の計算
var inverse = matrix;
inverse.Invert();