您的位置:首页 > 其它

如何判断一个指定的经纬度点是否落在一个多边形内

2011-10-25 14:29 1151 查看
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;

}

//解题思想用射线法

//该题思想是向由点P向x正方向发射一个射线,穿过多边形线段上的个数为奇数则在多边形内,偶数则在多边形外

//具体方法是:点的Y值大于等于多边形上某个线段的最小值且小于该线段上的最大值,在该线段上取一个y值为点P.y的点P1。如果P.x<P1.x ,则计数器加1,若计数器为奇数则在多边形内,若为偶数则在多边形外

private bool PointInFences(point pnt1, point[] fencePnts)

{

int j=0, cnt = 0;

for (int i = 0; i < fencePnts.Length; i++)

{

j = (i == fencePnts.Length - 1) ? 0 : j + 1;

if ((fencePnts[i].y!=fencePnts[j].y)&&(((pnt1.y >= fencePnts[i].y) && (pnt1.y < fencePnts[j].y)) || ((pnt1.y >= fencePnts[j].y) && (pnt1.y < fencePnts[i].y))) && (pnt1.x < (fencePnts[j].x - fencePnts[i].x) * (pnt1.y - fencePnts[i].y) / (fencePnts[j].y
- fencePnts[i].y) + fencePnts[i].x)) cnt++;

}

return (cnt%2>0)?true:false;

}

我的一哥们写的比较精炼的一个小程序。原程序没有考虑到点P与多边形上的某个平行x轴的线段的两个端点三点共线问题。我加了一个先决判断条件就是到线段不平行于x轴。

该方法构思巧妙:

1、向X轴正方向发射射线,先判断是否与多边形的线段相交,若相交点的X值大于P的x值,则计数器加1.

2、通过大于等于线段两个端点的最小Y值,小于线段两个端点的最大Y值,判断出射线与线段是否相交。——避免了P在线段的延长线上的情况对计算结果的困扰。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: