多边形电子围栏算法

     在日常生活工作中,我们经常接触到电子围栏,大部分的电子围栏基本上都是圆形的,想要知道某一个点是否在圆形区域内,算法很简单,只需要知道这个圆形区域的圆心坐标和被测点的坐标的距离是否小于半径即可。两点的距离小于半径,说明被测点在圆形区域内,反之则在圆形区域外。那如果围栏的区域形状不是圆形,而是一个不规则的多边形呢,那我们怎么知道被测点是否在多边形区域内。其实很简单,整体思想如下:

    从目标被测点引发一条竖直向上的射线,看这条射线和多边形所有线段的交点数目。如果有奇数个交点,则说明目标点在多边形内部,如果有偶数个交点,则说明目标点在多边形外部。此思路在特殊处理后适用于凸多边形,凹多边形,不规则多边形。但有几个特殊的情况需要处理。

1 当射线与线段的左边顶点相交时,我们认为射线与线段相交。当射线与线段的右边顶点相交时,我们认为射线与线段不相交。如下图所示:

2 当有竖直向上的线段时,我们认为该线段不与射线相交(包括射线和线段重叠的情况)。如:

示列代码如下:

#include <stdio.h>
#include <math.h>

struct Point_t{
double x_value;
double y_value;
};

//给定坐标围成多边形
struct Point_t p_tab[4]={
{10.0, 20.0}, //第0个点
{20.0, 30.0},
{30.0, 20.0},
{20.0, 10.0},
};

//被测点的坐标
struct Point_t testaaa = {
.x_value = 21.0,
.y_value = 19.0,
};

int equal(double a, double b)
{
    if((fabs(a-b)) <= (1E-6)){
        return 1;
	}
	return 0;
}

int Polygon_fence_check(struct Point_t Test, struct Point_t *refer, int point_num)
{
   int i;
   int next_i;
   int crossings_count = 0;
   double slope;
   unsigned char cond;
   if(refer = NULL){
       return -1;
}
   for(i = 0; i < point_num; i++){
   	   if((i+1)>= point_num){
           next_i = 0;
	   }else{
           next_i = i+1;
	   }
   	   //线段的横坐标一样,表示线段竖直。这种情况,我们认为被测点引发的竖直射线不会和此类线段相、交。包括射线和线段重叠。
	   if(equal(refer[i].x_value, refer[next_i].x_value) == 1){	   	   
			printf("point %d and point %d x_value is same\r\n", i, next_i);
            continue;		       
	   }
	   cond = 0;
	   //判断被测点的横坐标是否在某线段两顶点的横坐标区间内。注意:当线段左边顶点的横坐标与被测点的横坐标一样时,我们以为
	   //被测点的横坐标在线段两顶点的横坐标区间内;当线段右边顶点的横坐标与被测点的横坐标一样时,我们以为被测点的横
	   //坐标在线段两顶点的横坐标区间外。
       if(((refer[i].x_value <= Test.x_value)&&(Test.x_value < refer[next_i].x_value))
	   	||((refer[next_i].x_value <= Test.x_value)&&(Test.x_value < refer[i].x_value))){
           cond = 0x01;
	   }
	   
	   if(cond == 0x01){   
	   	   //当被测点的横坐标在两顶点的横坐标区间内时,计算线段上对应被测点横坐标的纵坐标。当这个纵坐标大于被测点的纵坐标时,
	   	   //我们以为射线与线段相交。
           slope = (refer[next_i].y_value - refer[i].y_value)/(refer[next_i].x_value - refer[i].x_value);
    	   if(Test.y_value < (slope*(Test.x_value - refer[i].x_value)+refer[i].y_value)){
               printf("crossing line num = %d\r\n", i);
               crossings_count++;	  
    	   }
	   }
	   
   }
   printf("crossings count = %d\r\n",crossings_count);
   return ((crossings_count%2) != 0);
}

int main(void)
{
   int flag;
    flag = Polygon_fence_check(testaaa, p_tab, 4);
	printf("flag = %d\r\n", flag);
    return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值