判断一个点是否在指定区域内

在图像处理时,我们会经常需要判断一个点是否位于多边形区域内,这里介绍2种比较巧妙的算法。

射线法

第一种是射线法,算法思想非常巧妙:从待判断的点向某一个方向引射线,计算和多边形交点的个数,如果个数是偶数或者0则点在多边形外,如果是奇数,则在多边形内,如下图:


这里有二种特殊情况:

1. 射线经过顶点:当射线经过顶点时,判断就会出现异常情况。

2. 点在边上:这种情况也不能用交点个数的奇偶性来判断了,要快速地判断这个点是否在边上。

C的实现如下:

参考自:Determining if a point lies on the interior of a polygon

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#define MIN(x,y) (x < y ? x : y)
#define MAX(x,y) (x > y ? x : y)
  
typedef struct {
    double x,y;
} Point;
  
int InsidePolygon(Point *polygon, int N,Point p)
{
   int counter = 0;
   int i;
   double xinters;
   Point p1,p2;
  
   p1 = polygon[0];
   for (i=1;i<=N;i++) {
     p2 = polygon[i % N];
     if (p.y > MIN(p1.y,p2.y)) { //低
       if (p.y <= MAX(p1.y,p2.y)) { //高
         if (p.x <= MAX(p1.x,p2.x)) { //右
           if (p1.y != p2.y) { //简单忽略平行X轴这种情况
             xinters = (p.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x; //交叉点坐标 参考./media/point-and-polygon/xinters.jpg
             if (p1.x == p2.x || p.x <= xinters)
               counter++;
           }
         }
       }
     }
     p1 = p2;
   }
  
   if (counter % 2 == 0)
     return 0;
   else
     return 1;
}

再来个C#版的

1
2
3
4
5
6
7
8
9
10
11
12
public static bool Contains( Point[] points, Point p )
{
    bool result = false ;
    for ( int i = 0; i < points.Length - 1; i++ )
    {
       if ( ( ( ( points[ i + 1 ].Y <= p.Y ) && ( p.Y < points[ i ].Y ) ) || ( ( points[ i ].Y <= p.Y ) && ( p.Y < points[ i + 1 ].Y ) ) ) && ( p.X < ( points[ i ].X - points[ i + 1 ].X ) * ( p.Y - points[ i + 1 ].Y ) / ( points[ i ].Y - points[ i + 1 ].Y ) + points[ i + 1 ].X ) )
       {
          result = !result;
       }
    }
    return result;
}

值得一提的是射线法对于带岛的多边形依然有效:


改进:传统的射线法一开始就直接计算点和多边形的交点个数,这样的话,会花费大量的时间来作拓扑关系的判断,我们可以首先计算出最小外包矩形,迅速排除不在矩形内部的点,然后再做上面的判断。

第二种是也很巧妙

如下图:


我们可以把多边形可以看做是一条从某点出发的闭合路,可以观察到在内部的点永远都在路的同一边。

给定线段的两个点P0(x0,y0)和P1(x1,y1),目标点P(x,y),它们有如下的关系:

计算(y - y0) (x1 - x0) - (x - x0) (y1 - y0)

如果答案小于0则说明P在线段的右边,大于0则在左边,等于0说明在线段上。

除了上面两种,还有很多方法

比如面积法:就是计算所有边和目标点组成的三角形面积和是否等于总的多边形面积,如果相等,则点在该区域的内部。

这种方法计算量较大,多边形的面积计算也是比较麻烦;

还有夹角法:判断所有边和目标点的夹角和是否为360度,计算量同样很大。


转自:http://vicdory.com/determining-if-a-point-lies-on-the-interior-of-a-polygon.html

要在Redis中判断一个点是否在坐标区域内,可以使用Redis的地理空间数据类型和相关命令。Redis支持存储和查询地理空间数据,使其成为一个强大的地理信息系统。 首先,你需要使用Redis的地理空间数据类型,例如有序集合(Sorted Set),来存储多边形区域的坐标点。你可以将每个坐标点作为一个成员,将其经度作为score。通过有序集合的score,可以快速对坐标点进行排序和范围查询。 接下来,你可以使用Redis的地理空间命令,如GEORADIUS,来判断一个点是否在多边形区域内。GEORADIUS命令可以根据指定的经度、纬度和半径,返回在指定范围内的坐标点。将要判断的点作为参数传递给GEORADIUS命令,并设置一个适当的半径,如果返回的结果中包含了这个点,那么就说明这个点在多边形区域内。 需要注意的是,Redis的地理空间命令默认使用的是WGS84坐标系,即经度和纬度使用的是度数。因此,在使用这些命令时,需要将点的经度和纬度转换为度数,并确保它们与多边形区域中的坐标点使用相同的坐标系。 总结来说,为了在Redis中判断一个点是否在坐标区域内,你可以使用Redis的地理空间数据类型和地理空间命令。将多边形区域的坐标点存储为有序集合,并使用GEORADIUS命令来查询指定范围内的坐标点,以判断一个点是否在多边形区域内。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值