2012-05-10 20 views
7

私はいくつかのポリゴンリスト項目(不規則な形)からなるDelphi(TCustomControlから継承)でカスタムコントロールを作成しています。アイテムごとにマウスイベントを実装する必要がありますが、まず、マウスの位置が指定されたポリゴン(array of TPoint)内にあるかどうかを検出できる必要があります。私はヒットテストメッセージ(WM_NCHITTEST)をキャッチしており、これがこの検証を行う必要がある場所です。私は多角形をいくつも持っているので、各ポリゴンアイテムをループし、このチェックを実行してマウスのX/Y位置がこのポリゴン内にあるかどうかを調べます。ポイントがポリゴン内にあるかどうかを確認しますか?

procedure TMyControl.WMNCHitTest(var Message: TWMNCHitTest); 
var 
    P: TPoint; //X/Y of Mouse 
    Poly: TPoints; //array of TPoint 
    X: Integer; //iterator 
    I: TMyListItem; //my custom list item 
begin 
    P.X:= Message.XPos; 
    P.Y:= Message.YPos; 
    for X := 0 to Items.Count - 1 do begin 
    I:= Items[X]; //acquire my custom list item by index 
    Poly:= I.Points; //acquire polygon points 

    //Check if Point (P) is within Polygon (Poly)...? 

    end; 
end; 
+0

ちょうど指摘すると、 'P.X'と' P.Y'を割り当てた直後に 'P:= ScreenToClient(P);というコードが1行欠けています。これは、これらの点を画面に関連するものからコントロールに対するものに変換します。 –

+0

もちろん 'P:= ScreenToClient(Point(Message.XPos、Message.YPos));'(3行のコードを1つに変えて) –

答えて

15

あなたはPtInRegionを使用することができます。http://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm

ほとんどのコンピュータグラフィックスクラスは一例としてこれを使用します。

function PointInPolygon(Point: TPoint; const Polygon: array of TPoint): Boolean; 
var 
    rgn: HRGN; 
begin 
    rgn := CreatePolygonRgn(Polygon[0], Length(Polygon), WINDING); 
    Result := PtInRegion(rgn, Point.X, Point.Y); 
    DeleteObject(rgn); 
end; 
+0

これは私の最初のアイデアでした。私は、GDIリージョンを作成するオーバーヘッドがあまりにも悪くないと思います(?)。 –

+4

@アンドレアス私はオーバーヘッドが悪いとは思わない。 GDI領域は非常に軽量でなければなりません。問題があった場合は、ポリゴンの横にリージョンをキャッシュすることができます。 –

+0

優秀!オーバーヘッドの問題はほとんどありません。なぜなら、このコントロールには20以上のリスト項目が存在するとは考えていないからです(これはすでにこのコントロールにとって大きな数字です)。 –

5

あなたがここで見つけるレイキャスティングアルゴリズムを使用することができます。

1

点がポリゴンの内側にあるかどうかを確認するには、その点を通る水平線を想像し、左から右に向かって、この想像線がポリゴンと交差する回数を数えます。点を打つ前に多角形の数が奇数である場合、点が内側にある場合、その点が多角形の外側にある場合、点は内側にあります。

0

私たちが広範囲に使用する別の手法があります。これは、数学をまったく含まず、あらゆる形状の非常に複雑な埋め込みコントロールをまったく処理できません。ユーザーがクリックできるように、すべての部分が色分けされた(下の図に示すように)コントロールの画面外のイメージを持つだけです。

マウスを動かすと、単にマウスの下のピクセルの色をオフスクリーンイメージで見てください。これは、マウスの上にあるボタン/コントロール、さまざまな部品の色の

Color mask

//擬似コード

function MouseOverControl(LocalMousePos:TPoint):ControlID; 
begin 
    //sanity check 
    Result:=IDNull; 
    if (LocalMouse.X < 0) or (LocalMouse.X > ControlWidth) or 
     (LocalMouse.Y < 0) or (LocalMouse.Y > ControlHeight) then 
      exit; 
    case OffScreenControlMask.Canvas.Pixels[LocalMousePos.X,LocalMousePos.Y] of 
    clwhite:exit; 
    clRed:result:=ControlIDOne; 
    clGreen:result:=ControlIDTwo; 
    clBlue:result:=ControlIDThree; 
    ... etc 
    end; 
end; 

注:取り付けカラーマスク画像は中央のボタンとの象限に分割5つの同一の円形のコントロールを表す(そしてそれらはすべて同じ色を使用するので私たちは各色の定数を持っており、マウスの右にある不規則なコントロールとその下のセットまたは四角いボタンのほか、単純なXPositionによってマウスが5つのうちのどれかを判別します。

関連する問題