1、理论支持:如果从需要判断的点出发的一条射线与该多边形的焦点个数为奇数,则该点在此多边形内,否则该点在此多边形外。(射线不能与多边形顶点相交)
2、编程思路:
该程序的思路是从A点出发向左做一条水平射线(平行于x轴,向X轴的反方向),判断与各边是否有焦点。
dLon1, dLon2, dLat1, dLat2分别表示边的起点和终点的经度和纬度(x轴和y轴)。
先判断A点是否在边的两端点d1和d2的水平平行线之间,不在则不可能有交点,继续判断下一条边。
在之间则说明可能与A点向左的射线有交点,接下来利用几何方法得到A点的水平直线与该边交点的x坐标。
然后判断交点的x坐标在A点的左侧还是右侧,左侧则总交点数加一,右侧则不在A点左射线上,继续判断下一条边。
3、原文代码如下(Dephi):
Type
TMyPoint = packed record
X : double;
Y : double;
end;
{*------------------------------------------------------------------------------
判 断指定的经纬度坐标点是否落在指定的多边形区域内
@param ALon 指定点的经度
@param ALat 指定点的纬度
@param APoints 指定多边形区域各个节点坐标
@return True 落在范围内 False 不在范围内
------------------------------------------------------------------------------*}
function IsPtInPoly(ALon, ALat: double; APoints: array of TMyPoint): Boolean;
var
iSum, iCount, iIndex: Integer;
dLon1, dLon2, dLat1, dLat2, dLon: double;
begin
Result := False;
if (Length(APoints) < 3) then
begin
Result := False;
Exit;
end;
iSum := 0;
iCount := Length(APoints);
for iIndex :=0 to iCount - 1 do
begin
if (iIndex = iCount - 1) then
begin
dLon1 := APoints[iIndex].X;
dLat1 := APoints[iIndex].Y;
dLon2 := APoints[0].X;
dLat2 := APoints[0].Y;
end
else
begin
dLon1 := APoints[iIndex].X;
dLat1 := APoints[iIndex].Y;
dLon2 := APoints[iIndex + 1].X;
dLat2 := APoints[iIndex + 1].Y;
end;
//以下语句判断A点是否在边的两端点的水平平行线之间,在则可能有交点,开始判断交点是否在左射线上
if ((ALat >= dLat1) and (ALat < dLat2)) or ((ALat>=dLat2) and (ALat < dLat1)) then
begin
if (abs(dLat1 - dLat2) > 0) then
begin
//得到 A点向左射线与边的交点的x坐标:
dLon := dLon1 - ((dLon1 -dLon2) * (dLat1 -ALat)) / (dLat1 - dLat2);
// 如果交点在A点左侧(说明是做射线与 边的交点),则射线与边的全部交点数加一:
if (dLon < ALon) then
Inc(iSum);
end;
end;
end;
if (iSum mod 2 <> 0) then
Result := True;
end;
(C#)
public bool IsPtInPoly(double ALon, double ALat, List<Point> APoints)
{
int iSum = 0, iCount;
double dLon1, dLon2, dLat1, dLat2, dLon;
if (APoints.Count < 3)
return false;
iCount = APoints.Count;
for (int i = 0; i < iCount - 1; i++)
{
if (i == iCount - 1)
{
dLon1 = APoints[i].X;
dLat1 = APoints[i].Y;
dLon2 = APoints[0].X;
dLat2 = APoints[0].Y;
}
else
{
dLon1 = APoints[i].X;
dLat1 = APoints[i].Y;
dLon2 = APoints[i + 1].X;
dLat2 = APoints[i + 1].Y;
}
//以下语句判断A点是否在边的两端点的水平平行线之间,在则可能有交点,开始判断交点是否在左射线上
if (((ALat >= dLat1) && (ALat < dLat2)) || ((ALat >= dLat2) && (ALat < dLat1)))
{
if (Math.Abs(dLat1 - dLat2) > 0)
{
//得到 A点向左射线与边的交点的x坐标:
dLon = dLon1 - ((dLon1 - dLon2) * (dLat1 - ALat)) / (dLat1 - dLat2);
// 如果交点在A点左侧(说明是做射线与 边的交点),则射线与边的全部交点数加一:
if (dLon < ALon)
iSum++;
}
}
}
if (iSum % 2 != 0)
return true;
return false;
}