1. 算法思路

判断平面内点是否在多边形内有多种算法,其中射线法是其中比较好理解的一种,而且能够支持凹多边形的情况。该算法的思路很简单,就是从目标点出发引一条射线,看这条射线和多边形所有边的交点数目。如果有奇数个交点,则说明在内部,如果有偶数个交点,则说明在外部。如下图所示:



算法步骤如下:

  1. 已知点point(x,y)和多边形Polygon的点有序集合(x1,y1;x2,y2;….xn,yn;);
  2. 以point为起点,以无穷远为终点作平行于X轴的射线line(x,y; -∞,y);循环取得多边形的每一条边side(xi,yi;xi+1,yi+1):

    1). 判断point(x,y)是否在side上,如果是,则返回true。

    2). 判断line与side是否有交点,如果有则count++。
  3. 判断交点的总数count,如果为奇数则返回true,偶数则返回false。

2. 具体实现

在具体的实现过程中,其实还有一个极端情况需要注意:当射线line经过的是多边形的顶点时,判断就会出现异常情况。针对这个问题,可以规定线段的两个端点,相对于另一个端点在上面的顶点称为上端点,下面是下端点。如果射线经过上端点,count加1,如果经过下端点,则count不必加1。具体实现如下:

#include<iostream>
#include <cmath>
#include <vector>
#include <algorithm> #define EPSILON 0.000001 using namespace std; //二维double矢量
struct Vec2d
{
double x, y; Vec2d()
{
x = 0.0;
y = 0.0;
}
Vec2d(double dx, double dy)
{
x = dx;
y = dy;
}
void Set(double dx, double dy)
{
x = dx;
y = dy;
}
}; //判断点在线段上
bool IsPointOnLine(double px0, double py0, double px1, double py1, double px2, double py2)
{
bool flag = false;
double d1 = (px1 - px0) * (py2 - py0) - (px2 - px0) * (py1 - py0);
if ((abs(d1) < EPSILON) && ((px0 - px1) * (px0 - px2) <= 0) && ((py0 - py1) * (py0 - py2) <= 0))
{
flag = true;
}
return flag;
} //判断两线段相交
bool IsIntersect(double px1, double py1, double px2, double py2, double px3, double py3, double px4, double py4)
{
bool flag = false;
double d = (px2 - px1) * (py4 - py3) - (py2 - py1) * (px4 - px3);
if (d != 0)
{
double r = ((py1 - py3) * (px4 - px3) - (px1 - px3) * (py4 - py3)) / d;
double s = ((py1 - py3) * (px2 - px1) - (px1 - px3) * (py2 - py1)) / d;
if ((r >= 0) && (r <= 1) && (s >= 0) && (s <= 1))
{
flag = true;
}
}
return flag;
} //判断点在多边形内
bool Point_In_Polygon_2D(double x, double y, const vector<Vec2d> &POL)
{
bool isInside = false;
int count = 0; //
double minX = DBL_MAX;
for (int i = 0; i < POL.size(); i++)
{
minX = std::min(minX, POL[i].x);
} //
double px = x;
double py = y;
double linePoint1x = x;
double linePoint1y = y;
double linePoint2x = minX -10; //取最小的X值还小的值作为射线的终点
double linePoint2y = y; //遍历每一条边
for (int i = 0; i < POL.size() - 1; i++)
{
double cx1 = POL[i].x;
double cy1 = POL[i].y;
double cx2 = POL[i + 1].x;
double cy2 = POL[i + 1].y; if (IsPointOnLine(px, py, cx1, cy1, cx2, cy2))
{
return true;
} if (fabs(cy2 - cy1) < EPSILON) //平行则不相交
{
continue;
} if (IsPointOnLine(cx1, cy1, linePoint1x, linePoint1y, linePoint2x, linePoint2y))
{
if (cy1 > cy2) //只保证上端点+1
{
count++;
}
}
else if (IsPointOnLine(cx2, cy2, linePoint1x, linePoint1y, linePoint2x, linePoint2y))
{
if (cy2 > cy1) //只保证上端点+1
{
count++;
}
}
else if (IsIntersect(cx1, cy1, cx2, cy2, linePoint1x, linePoint1y, linePoint2x, linePoint2y)) //已经排除平行的情况
{
count++;
}
} if (count % 2 == 1)
{
isInside = true;
} return isInside;
} int main()
{
//定义一个多边形(六边形)
vector<Vec2d> POL;
POL.push_back(Vec2d(268.28, 784.75));
POL.push_back(Vec2d(153.98, 600.60));
POL.push_back(Vec2d(274.63, 336.02));
POL.push_back(Vec2d(623.88, 401.64));
POL.push_back(Vec2d(676.80, 634.47));
POL.push_back(Vec2d(530.75, 822.85));
POL.push_back(Vec2d(268.28, 784.75)); //将起始点放入尾部,方便遍历每一条边 //
if (Point_In_Polygon_2D(407.98, 579.43, POL))
{
cout << "点(407.98, 579.43)在多边形内" << endl;
}
else
{
cout << "点(407.98, 579.43)在多边形外" << endl;
} //
if (Point_In_Polygon_2D(678.92, 482.07, POL))
{
cout << "点(678.92, 482.07)在多边形内" << endl;
}
else
{
cout << "点(678.92, 482.07)在多边形外" << endl;
} return 0;
}

运行结果如下:

3. 改进空间

  1. 很多情况下在使用该算法之前,需要一个快速检测的功能:当点不在多边形的外包矩形的时候,那么点一定不在多边形内。
  2. 判断点在线上函数IsPointOnLine()和判断线段相交函数IsIntersect()这里并不是最优算法,可以改成向量计算,效率应该更高。

判断点在多边形内算法的C++实现的更多相关文章

  1. hdu 1756:Cupid's Arrow(计算几何,判断点在多边形内)

    Cupid's Arrow Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tot ...

  2. zoj 1081 判断点在多边形内

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=81Points Within Time Limit: 2 Second ...

  3. php之判断点在多边形内的api

    1.判断点在多边形内的数学思想:以那个点为顶点,作任意单向射线,如果它与多边形交点个数为奇数个,那么那个点在多边形内,相关公式: <?php class AreaApi{ //$area是一个多 ...

  4. POJ 2318 TOYS | 二分+判断点在多边形内

    题意: 给一个矩形的区域(左上角为(x1,y1) 右下角为(x2,y2)),给出n对(u,v)表示(u,y1) 和 (v,y2)构成线段将矩形切割 这样构成了n+1个多边形,再给出m个点,问每个多边形 ...

  5. ZOJ 1081 Points Within | 判断点在多边形内

    题目: 给个n个点的多边形,n个点按顺序给出,给个点m,判断m在不在多边形内部 题解: 网上有两种方法,这里写一种:射线法 大体的思想是:以这个点为端点,做一条平行与x轴的射线(代码中射线指向x轴正方 ...

  6. R树判断点在多边形内-Java版本

    1.什么是RTree 待补充 2.RTree java依赖 rtree的java开源版本在GitHub上:https://github.com/davidmoten/rtree 上面有详细的使用说明 ...

  7. 点在多边形内算法,C#判断一个点是否在一个复杂多边形的内部

    判断一点是否在不规则图像的内部算法,如下图是由一个个点组成的不规则图像,判断某一点是否在不规则矩形内部,先上效果图 算法实现如下,算法简单,亲试有效 public class PositionAlgo ...

  8. hdu 1756 判断点在多边形内 *

    模板题 #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> ...

  9. A Round Peg in a Ground Hole - POJ 1584 (判断凸多边形&判断点在多边形内&判断圆在多边形内)

    题目大意:首先给一个圆的半径和圆心,然后给一个多边形的所有点(多边形按照顺时针或者逆时针给的),求,这个多边形是否是凸多边形,如果是凸多边形在判断这个圆是否在这个凸多边形内.   分析:判断凸多边形可 ...

随机推荐

  1. 微服务架构 - 巧妙获取被墙的Docker镜像

    在国内由于种种原因,有些Docker镜像直接是获取不到的,特别是k8s中的一些镜像.本人在部署k8s中的helm组件时需要获取tiller镜像,如果直接用如下命令: docker pull gcr.i ...

  2. javascript数组的常用算法解析

    一.不改变原数组,返回新数组(字符串) 1.concat()   连接两个或者多个数组,两边的原始数组都不会变化,返回的是被连接数组的一个副本. 2.join()  把数组中所有的元素放入到一个字符串 ...

  3. asp.net core系列 53 IdentityServer4 (IS4)介绍

    一.概述 在物理层之间相互通信必须保护资源,需要实现身份验证和授权,通常针对同一个用户存储.对于资源安全设计包括二个部分,一个是认证,一个是API访问. 1 认证 认证是指:应用程序需要知道当前用户的 ...

  4. 《前端之路》之 前端图片 类型 & 优化 & 预加载 & 懒加载 & 骨架屏

    目录 09: 前端图片 类型 & 优化 & 预加载 & 懒加载 & 骨架屏 09: 前端图片 类型 & 优化 & 预加载 & 懒加载 & ...

  5. MongoDB【快速入门】

    1.MongDB 简介 MongoDB(来自于英文单词"Humongous",中文含义为"庞大")是可以应用于各种规模的企业.各个行业以及各类应用程序的开源数据 ...

  6. .Net 反射学习

    Why?为什么使用反射 MVC ORM EF 都是用的反射.反射可以让程序的扩展性,灵活性得到加强.一起即可动态创建   what 反射原理    动态加载类库 ,先添加引用类库,或者复制debug里 ...

  7. android 系统dialog的应用

    应用示例如下: /* * 提示类型dialog */ private void dialog1(){ AlertDialog.Builder builder = new AlertDialog.Bui ...

  8. 还在用AIDL吗?试试EasyMessenger吧

    EasyMessenger 直达Github项目地址 一款用于Android平台的基于Binder的进程间通信库,采用annotationProcessor生成IPC通信需要的代码.EasyMesse ...

  9. ReactNative之从“拉皮条”来看RN中的Spring动画

    上篇博客我们聊了RN中关于Timing的动画,详情请参见于<ReactNative之结合具体示例来看RN中的的Timing动画>本篇博客我们将从一个“拉皮条”的一个动画说起,然后来看一下R ...

  10. 【死磕 Spring】----- IOC 之 获取验证模型

    原文出自:http://cmsblogs.com 在上篇博客[死磕Spring]----- IOC 之 加载 Bean 中提到,在核心逻辑方法 doLoadBeanDefinitions()中主要是做 ...