ベジェ曲線の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段ほど潜ればちゃんと交差判定できます。小細工をすればもっと浅くできます。
これで、画面内に有るか無いか仮想化に役立てようという考えです。