エクセルのグループ化を真似したくていろいろ試している続き
マウスドラッグで四角形の範囲を作ってその範囲に重なったものを取得するっていうだいぶ前の方法
WPFとVB.NET、エクセルのグループ化とグループ化解除を真似したい4 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14203583.html
http://blogs.yahoo.co.jp/gogowaten/14203583.html
この時の方法だとコントロールを回転とか変形をさせた時にうまくいかないことがわかった(’・ω・‘)
これはRotateTransformで変形させても変わるのは見た目だけで中身は変わっていないのに、その中身と判定しているから
解決するには見た目通りの形を取得する必要があるかなと思って
なんとかできたのが今回の
正方形の赤が元の形で
斜めになっている長方形は元の形から横拡大率2.0、縦拡大率0.7、右に30度回転
これをいろいろな選択範囲で判定している
下のステータスバーは判定結果を表示している
ググっていたら
VisualTreeHelper.HitTestっていうのを使うのもあるみたいだったけど難しくてわからなかった(小並感)CallBackってのがわからん
だから別の方法
前回まで判定に使ったのはRectクラス、つまり長方形で判定していた
回転させると菱型になるからRectは使えないので今回はGeometryクラス
GeometryクラスのFillContainsWithDetailメソッドを使ってコントロール同士の重なりの判定をしている
この便利なメソッドFillContainsWithDetail、これにたどり着くまでが長かった
ヒントになったのがこちら
片鱗懐古のブログ: wpf : UIElement.InputHitTestを試したら予想と違った動作ありがとうございます!
http://pieceofnostalgy.blogspot.jp/2011/11/wpf-uielementinputhittest.html
デザイン画面とXAML
正方形のは目印用
拡大回転させた長方形のほうが目的のものになる
このふたつは見た目が違うだけで中身は同じ大きさ同じ位置
MainWindowのVBコード
FillContainsWithDetailメソッドは2つのGeometryを渡すと重なり具合を比較して結果を返してくれる
変形させた赤Borderの見た目通りの形をしたGeometryの作成のための4頂点を取得
Geometryってのは順番が付いた点の集合みたいなものかなあ、順番に従って点を直線や曲線で繋いでいくと図形ができあがる感じ
なので見た目通りのGeometryを作るには各頂点座標が必要
各頂点は元の位置から移動している、それぞれどこに移動したか取得するには
TransformToVisualで得られるGeneralTransformを使う
赤Borderは
canvas1に表示している
Transformで変形させているので
39行目で赤Borderのcanvas1に対するGeneralTransformを取得して
40行目で元の左上の頂点(0,0)をGeneralTransformのTransformメソッドを使ってどこに移動しているか取得している
赤Borderがcanvas1上のどこに表示されていても左上の頂点がどこにあるのか取得するときは(0,0)を変形させればいいみたい
同じように他の3つの頂点も取得
4隅の頂点座標がわかったらこれを使ってGeometryを作る、正確にはPathGeometryを作った、この辺はよくわかっていなくて
ジオメトリの概要
https://msdn.microsoft.com/ja-jp/library/ms751808(v=vs.110).aspx
ここ見ながら書いた
大事なのはPathFigureのIsClosedとIsFilledにはTrueを指定する
IsClosedは最初の点と最後の点を直線で繋いで図形を閉じるかどうか
IsFilledは図形の閉じた内側を塗りつぶすかどうかを指定しているみたい
とくにIsFilledはTrueにしないとFillContainsWithDetailで期待通りの判定が返ってこなかった
ここまでで赤Borderの見た目通りの形をしたGeometryは完成
目印用の黒枠表示
完成したGeometryは本当に期待通りの形になっているのかの確認用
Pathを作ってそのDataにGeometryを指定して表示している
赤Borderの外側の黒枠がそれ
ここからcanvas1のマウスイベントを使った
マウスドラッグ移動で範囲選択用の枠表示
Handles canvas1.MouseLeftButtonDown
83行目、マウスドラッグ移動の最初の点を記録
それ以降はステータスバー表示とかの初期化
移動開始地点と今の場所の2点を使ってRectを作成
108行目までは初期化とかしているだけで判定は111行目から
全く重ならなかった時は
Empty
この辺
Handles canvas1.MouseMove、マウス移動中
Rectを使ってRectangleGeometryを作成
それを選択範囲枠用のselectPathのDataに指定
ってそのままだな、こんなふうにGeometryにはいくつかの種類があって
RectangleGeometryはRectから簡単に作ることができる
この時点で比較する2つのGeometryは完成しているけど、今回はマウス移動中に判定しない
Handles canvas1.MouseLeftButtonUp、左クリックを離した時
マウスドラッグ終了に判定
2つのGeometry
selectPathはマウスドラッグで作成した選択範囲用の四角枠、そのDataにはGeometryなのでこれをg1
bRedGeometryは赤BorderのGeometry、これをg2
114行目、ここでやっとFillContainsWithDetailを使って判定
Dim iDetail As IntersectionDetail = g1.FillContainsWithDetail(g2)
これで返ってくる判定結果の種類はだいたい以下の4つ
- Empty 重なっている部分はない
- FullyContains g2のすべてはg1の中に入っている
- FullyInside g1のすべてはg2の中に入っている
- Intersects 一部が重なっている
今回の目的は重なりの有無だから、Emptyかそれ以外がわかればいいことになる
つまりEmpty以外なら重なっている
これはg1、g2を入れ替えて
Dim iDetail As IntersectionDetail = g2.FillContainsWithDetail(g1)
ってしても今回の目的なら同じかも
一時停止して中を見てみる
赤BorderのGeometry作成時
マウスドラッグで範囲指定した時
この時
こうしてみると同じGeometryでもRectangleGeometryとPathGeometryでは
ずいぶん感じが違う、にもかかわらずしっかり判定してくれるFillContainsWithDetailメソッドはすごいなあ
で、この結果は
こうなる
Intersectsは一部分が重なっていた判定
選択範囲のすべてが赤Borderの中に入っているときは
FullyInside
こんな感じで選択範囲の中に赤Borderが全て入った時は
FullyContains
なんかこれだけで楽しい
ステータスバーに表示しているp0(n,n)とかは、重なり部分を水色で塗りつぶしに使っているGeometryの各頂点座標
これの処理は
GeometryクラスのCombineメソッドを使うと2つのGeometryを判定(合成?)した結果のPathGeometryを返してくれる
今回使っているのが2つが重なった部分だけの形になるPathGeometryを返してくれるGeometryCombineMode.Intersect、128行目
これで得たPathGeometryをIntersectPathのDataにして水色で塗りつぶし表示
PathGeometryの中に入っている各頂点座標をp0からの連番で表示
これは
方法 : 結合したジオメトリを作成するここを参照
https://msdn.microsoft.com/ja-jp/library/ms746682(v=vs.110).aspx
今回のコード一式
Wpf_test131_ヒットテスト - Visual Studio Team Services
https://gogowaten.visualstudio.com/WPF/_git/WPF_test8?path=%2FWpf_test131_%E3%83%92%E3%83%83%E3%83%88%E3%83%86%E3%82%B9%E3%83%88&version=GBmaster&_a=contents
https://gogowaten.visualstudio.com/WPF/_git/WPF_test8?path=%2FWpf_test131_%E3%83%92%E3%83%83%E3%83%88%E3%83%86%E3%82%B9%E3%83%88&version=GBmaster&_a=contents
関連記事
前回
WPFとVB.NET、エクセルのグループ化とグループ化解除を真似したい6 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14215386.html
WPFとVB.NET、エクセルのグループ化とグループ化解除を真似したい6 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14215386.html
5年後はC#で