ベジェ曲線のHitTest
WPFにあまり任せてはいけないのがベジェ曲線のHitTestです。
几帳面で抜け目ありませんが、きわめて低速です。
真面目に方程式を解く手法ももちろんあるのですが、実はあんまり工夫しないでも、そこそこに優良なコードは書けます。
概ねこんなノリです。動かしてないので間違っていたらすみません。
/// <summary> /// 矩形とベジェの交差判定 /// </summary> /// <param name="v">Vecter[4]で、始点、制御点1、制御点2、終点</param> /// <param name="rect">交差しているか判定したい範囲。スタックに山積みさせないために ref 。面積が0は不可</param> /// <returns>矩形とヒットしている場合true</returns> /// <remarks></remarks> bool HitTestBezier(Vector[] v, ref Rect rect) { var p0 = new Point(v[0].X, v[0].Y); var p3 = new Point(v[3].X, v[3].Y); // 始点か終点を含んでいれば、Hitしている。 if (rect.Contains(p0) || rect.Contains(p3)) return true; var area = new Rect(p0, p3); area.Union(new Rect(new Point(v[1].X,v[1].Y),new Point(v[2].X,v[2].Y))); // ここらへんで小細工の余地はあります。幅や高さが1未満だったら直線と大差ないとか、いろいろ。 // 交差している可能性があるケースを判定 if(rect.IntersectsWith(area)) { var v01 = (v[0] + v[1]) / 2; var v12 = (v[1] + v[2]) / 2; var v23 = (v[2] + v[3]) / 2; var v0112 = (v01 + v12) / 2; var v1223 = (v12 + v23) / 2; var c = (v0112 + v1223) / 2; // 2分割してさらに探査 return HitTestBezier(new[] { v[0], v01, v0112, c }, ref rect) || HitTestBezier(new[] { c, v1223, v23, v[3] }, ref rect); } // 可能性が無い return false; }
とりあえず、WPFに丸任せするよりは高速です。お試しください。
長さが20億ピクセルくらいあるベジェ曲線でも最悪32段ほど潜ればちゃんと交差判定できます。小細工をすればもっと浅くできます。
これで、画面内に有るか無いか仮想化に役立てようという考えです。