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;
4

4 回答 4

16

您可以使用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;
于 2012-05-10T19:25:55.173 回答
5

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

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

于 2012-05-10T19:27:59.577 回答
2

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

于 2014-03-20T10:02:57.883 回答
0

还有另一种我们广泛使用的技术,它根本不涉及任何数学,并且可以处理任何形状的极其复杂的嵌入式控件。只需有一个控件的屏幕外图像,所有部件都用颜色编码(如下图所示),用户可以单击。

当他们移动鼠标时,只需在我们的屏幕外图像中查看鼠标下方像素的颜色,它就可以准确地告诉我们他们在哪个按钮/控件上方——白色表示未超过它,任何一系列颜色表示各种零件。

彩色蒙版

//伪代码

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)以及右侧的附加不规则控件和下方的一组或矩形按钮。

于 2017-03-26T23:44:15.527 回答