确定一个点是否在多边形内?

时间:2012-05-10 19:21:07

标签: delphi custom-controls delphi-xe2 polygon

我正在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;

4 个答案:

答案 0 :(得分:15)

您可以使用PtInRegion

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;

答案 1 :(得分:5)

您可以使用此处的光线投射算法:http://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm

大多数计算机图形类都以此为例。

答案 2 :(得分:1)

检查点是否在多边形内部可以通过想象通过该点的水平线,然后从左到右计算该想象线穿过多边形的次数来完成。如果在点击点之前多边形交叉的数量是奇数,则点在内部,如果即使那么点在多边形之外。

答案 3 :(得分: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;

注意:附加的颜色蒙版图像代表五个相同的圆形控件,分为带有中心按钮的象限(因为它们都使用相同的颜色,我们对每种颜色都有常量,我们确定鼠标中五个中的哪一个结束通过一个简单的XPosition)以及右边的一个额外的不规则控制和下面的一组或矩形按钮。