7

Winform上の2つのオブジェクトの間に矢印が描かれています。

私のマウスが現在この線の上または近くにあることを確認する最も簡単な方法は何でしょうか。

マウスポイントが2つのポイントによって定義および外挿された正方形と交差するかどうかをテストすることを検討しましたが、これは2つのポイントのx値またはy値が非常に似ている場合にのみ実行可能です。

また、この問題はおそらく単純な三角法ではなく線形代数の領域にあると思います。行列のより単純な側面を覚えていますが、この問題は線形代数の知識を超えています。

一方、.NETライブラリがこの機能に対応できる場合は、さらに優れています。

編集 答えてくれてありがとう、答えとしてタグ付けされるに値するいくつかの非常に良いものがありました。

描画された任意の形状に適用できるので、Coincoinの回答を受け入れたものとして選択しましたが、グラフィックパスとペンを新しくするよりも単純な方程式を使用した方がはるかに効率的であるため、TimRobinsonの方程式を実装することになりました。私の場合、1-nの異なる関係のためにonMouseMoveでそれを行う必要があります(明らかに、いくつかのキャッシングと最適化がありますが、ポイントはまだ残っています)

方程式の主な問題は、線が無限大として扱われるように見えることでした。そのため、境界テストも追加しました。

興味のある人のためのコード(最初のカット、おそらく少し調整します)は以下のとおりです

    if (Math.Sqrt( Math.Pow(_end.X - _start.X, 2) + 
           Math.Pow(_end.Y - _start.Y, 2) ) == 0)
    {
        _isHovering =
            new RectangleF(e.X, e.Y, 1, 1).IntersectsWith(_bounds);
    }
    else
    {
        float threshold = 10.0f;

        float distance = (float)Math.Abs( 
            ( ( (_end.X - _start.X) * (_start.Y - e.Y) ) -
            ( (_start.X - e.X) * (_end.Y - _start.Y) ) ) /
            Math.Sqrt( Math.Pow(_end.X - _start.X, 2) + 
            Math.Pow(_end.Y - _start.Y, 2) ));

        _isHovering = (
            distance <= threshold &&
                new RectangleF(e.X, e.Y, 1, 1).IntersectsWith(_bounds)
            );
    }

_boundsは次のように定義されます。

    _bounds = new Rectangle(
    Math.Min(_start.X, _end.X),
    Math.Min(_start.Y, _end.Y),
    Math.Abs(_start.X - _end.X), Math.Abs(_start.Y - _end.Y));
4

5 に答える 5

7

任意の描画形状で簡単にヒットテストを行いたい場合は、描画を含むパスを作成し、パスをワイド化して、フレームワーク関数のみを使用して可視性テストを行うことができます。

たとえば、ここでは次の行を使用してパスを作成します。

GraphicsPath path = new GraphicsPath();

path.AddLine(x1, y1, x2, y2);
path.CloseFigure();

次に、パスを広げて、ヒットテスト用の領域を作成します。

path.Widen(new Pen(Color.Black, 3));
region = new Region(path);

最後に、ヒットテスト:

region.IsVisible(point);

この方法の利点は、スプライン、矢印、円弧、パイ、またはGDI+で描画できるほとんどすべてのものに簡単に拡張できることです。HitTestとロジックの両方で同じパスをDraw抽出することにより、同じパスを使用できます。

すべてを組み合わせたコードは次のとおりです。

public GraphicsPath Path
{
    get { 
        GraphicsPath path = new GraphicsPath();
        path.AddLine(x1, y1, x2, y2);
        path.CloseFigure();

        return path;
    }
}

bool HitTest(Point point)
{
    using(Pen new pen = Pen(Color.Black, 3))
    using(GraphicsPaht path = Path)
    {
        path.Widen(pen);

        using(Region region = new Region(path))
            return region.IsVisible(point);
    }
}


void Draw(Graphics graphics)
{
    using(Pen pen = new Pen(Color.Blue, 0))
    using(GraphicsPaht path = Path)
        graphics.DrawPath(pen, path);
}
于 2010-03-19T20:33:36.200 に答える
4

「マウスがこの線の上に浮かんでいますか?」と答えるには、点線の交点を確認する必要があります。ただし、「マウスは線の近くにありますか?」と尋ねているので、マウスの点と線の間の距離を計算したいようです。

ポイントライン距離のかなり徹底的な説明は次のとおりです。http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html

この式をコードに実装する必要があると思います:(wolfram.comから盗まれました)

どこ:

  • (x0、x0)はマウスポインタの位置です
  • (x1、y1)は行の一端です
  • (x2、y2)は行のもう一方の端です
  • |n|Math.Abs(n)
  • 下半分はMath.Sqrt
  • 必要に応じて無視でき|v.r|ます
于 2010-03-19T20:25:38.517 に答える
2

直線の傾き切片の式(y = mx + b)を計算し、それを使用してマウスの座標をテストします。yの周りに範囲を簡単に設定して、「近い」かどうかを確認できます。

サンプル用に編集します。

私はこのようなものがうまくいくと思います:

PointF currentPoint;
PointF p1, p2;
float threshold = 2.0f;
float m = (p1.Y - p2.Y) / (p1.X - p2.X);
float b = p1.Y - (m * p1.X);

if (Math.Abs(((m * currentPoint.X) + b) - currentPoint.Y) <= threshold)
{
    //On it.
}
于 2010-03-19T20:29:18.817 に答える
1

理想的なパスに平行な2本の(概念上の)境界線を作成する必要があります。次に、マウスの位置ごとに、マウスがそれらの線によって形成されるチャネルの外側にあるか内側にあるかを計算するだけで済みます。

マウスからメインラインまでの距離を計算する必要はありません。

于 2010-03-19T20:26:22.143 に答える
0

MouseEnter(オブジェクト送信者、EventArgs e)を確認してください。コントロールエリアに「入る」ときにトラップします。

于 2010-03-19T20:24:42.643 に答える