判断点在多边形内算法的C++实现
1. 算法思路
判断平面内点是否在多边形内有多种算法,其中射线法是其中比较好理解的一种,而且能够支持凹多边形的情况。该算法的思路很简单,就是从目标点出发引一条射线,看这条射线和多边形所有边的交点数目。如果有奇数个交点,则说明在内部,如果有偶数个交点,则说明在外部。如下图所示:
算法步骤如下:
- 已知点point(x,y)和多边形Polygon的点有序集合(x1,y1;x2,y2;….xn,yn;);
- 以point为起点,以无穷远为终点作平行于X轴的射线line(x,y; -∞,y);循环取得多边形的每一条边side(xi,yi;xi+1,yi+1):
1). 判断point(x,y)是否在side上,如果是,则返回true。
2). 判断line与side是否有交点,如果有则count++。 - 判断交点的总数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. 改进空间
- 很多情况下在使用该算法之前,需要一个快速检测的功能:当点不在多边形的外包矩形的时候,那么点一定不在多边形内。
- 判断点在线上函数IsPointOnLine()和判断线段相交函数IsIntersect()这里并不是最优算法,可以改成向量计算,效率应该更高。
判断点在多边形内算法的C++实现的更多相关文章
- hdu 1756:Cupid's Arrow(计算几何,判断点在多边形内)
Cupid's Arrow Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tot ...
- zoj 1081 判断点在多边形内
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=81Points Within Time Limit: 2 Second ...
- php之判断点在多边形内的api
1.判断点在多边形内的数学思想:以那个点为顶点,作任意单向射线,如果它与多边形交点个数为奇数个,那么那个点在多边形内,相关公式: <?php class AreaApi{ //$area是一个多 ...
- POJ 2318 TOYS | 二分+判断点在多边形内
题意: 给一个矩形的区域(左上角为(x1,y1) 右下角为(x2,y2)),给出n对(u,v)表示(u,y1) 和 (v,y2)构成线段将矩形切割 这样构成了n+1个多边形,再给出m个点,问每个多边形 ...
- ZOJ 1081 Points Within | 判断点在多边形内
题目: 给个n个点的多边形,n个点按顺序给出,给个点m,判断m在不在多边形内部 题解: 网上有两种方法,这里写一种:射线法 大体的思想是:以这个点为端点,做一条平行与x轴的射线(代码中射线指向x轴正方 ...
- R树判断点在多边形内-Java版本
1.什么是RTree 待补充 2.RTree java依赖 rtree的java开源版本在GitHub上:https://github.com/davidmoten/rtree 上面有详细的使用说明 ...
- 点在多边形内算法,C#判断一个点是否在一个复杂多边形的内部
判断一点是否在不规则图像的内部算法,如下图是由一个个点组成的不规则图像,判断某一点是否在不规则矩形内部,先上效果图 算法实现如下,算法简单,亲试有效 public class PositionAlgo ...
- hdu 1756 判断点在多边形内 *
模板题 #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> ...
- A Round Peg in a Ground Hole - POJ 1584 (判断凸多边形&判断点在多边形内&判断圆在多边形内)
题目大意:首先给一个圆的半径和圆心,然后给一个多边形的所有点(多边形按照顺时针或者逆时针给的),求,这个多边形是否是凸多边形,如果是凸多边形在判断这个圆是否在这个凸多边形内. 分析:判断凸多边形可 ...
随机推荐
- Vue.js-08:第八章 - 组件的基础知识
一.前言 在之前的学习中,我们对于 Vue 的一些基础语法进行了简单的了解,通过之前的代码可以清晰的看出,我们在使用 Vue 的整个过程,最终都是在对 Vue 实例进行的一系列操作. 这里就会引出一个 ...
- python中线程和进程(二)
目录 线程同步 Event Lock RLock Condition Barrier semaphore GIL 线程同步 线程同步,即线程之间协同工作,一个线程访问某些数据时,其他线程不能访问这些数 ...
- user 不在 sudoers 文件中。此事将被报告。
在使用sudo -i或su root命令时,被提示出“user不在 sudoers 文件中.此事将被报告”的错误信息.这是因为当前登录的账号不在sudo权限里面.sudo命令可以让你以root身份执行 ...
- Windows上搭建远程访问服务
Windows上搭建远程访问服务 转自:https://blog.51cto.com/13871378/2153308?source=dra 概述:允许客户机通过拨号连接或虚拟专用网连接到公司局域网, ...
- 知名区块链人脸识别公司iFace Chain [爱妃链] 支招,如何防止钱包数字币被盗...
最近众多钱包发行方跑路频发,让非常多的用户蒙受巨大经济损失,知名区块链人脸识别公司iFace Chain [爱妃链] 前日做客某区块链媒体为网友支招,如何防止钱包数字币被盗. 那么,用户怎么降低Tok ...
- redis的hash类型!!!!
Hash类型 redsi的hash是基本类型之一,键值本身又是一对键值结构,是string类型的field和value的映射表,或者说是集合,适合存储对象. Hash的增操作 127.0.0.1:63 ...
- 【Netty】(5)源码 Bootstrap
[Netty]5 源码 Bootstrap 上一篇讲了AbstractBootstrap,为这篇做了个铺垫. 一.概述 Bootstrap 是 Netty 提供的一个便利的工厂类, 我们可以通过它来完 ...
- 使用C#+XPath+HtmlAgilityPack轻松搞一个资源下载器
HtmlAgilityPack简介 HtmlAgilityPack是一个开源的解析HTML元素的类库,最大的特点是可以通过XPath来解析HMTL,如果您以前用C#操作过XML,那么使用起HtmlAg ...
- Linux+.Net Core+Nginx(在Linux上使用Nginx反向代理.Net Core 项目)
Linux+.Net Core+Nginx 之前的文章中有提到关于使用Nginx在linux来实现反向代理,今天我们继续加点料.在Centos7中部署.NetCore,然后使用Nginx进行反向代理! ...
- 总结http get和post的区别
这个问题几乎面试的时候都会问到,是一个老生常谈的话题,然而随着不断的学习,对于以前的认识有很多误区,所以还是需要不断地总结的,学而时习之,不亦说乎. 什么是http? get.post常见的区别 ge ...