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。具体实现如下:

  1. #include<iostream>
  2. #include <cmath>
  3. #include <vector>
  4. #include <algorithm>
  5. #define EPSILON 0.000001
  6. using namespace std;
  7. //二维double矢量
  8. struct Vec2d
  9. {
  10. double x, y;
  11. Vec2d()
  12. {
  13. x = 0.0;
  14. y = 0.0;
  15. }
  16. Vec2d(double dx, double dy)
  17. {
  18. x = dx;
  19. y = dy;
  20. }
  21. void Set(double dx, double dy)
  22. {
  23. x = dx;
  24. y = dy;
  25. }
  26. };
  27. //判断点在线段上
  28. bool IsPointOnLine(double px0, double py0, double px1, double py1, double px2, double py2)
  29. {
  30. bool flag = false;
  31. double d1 = (px1 - px0) * (py2 - py0) - (px2 - px0) * (py1 - py0);
  32. if ((abs(d1) < EPSILON) && ((px0 - px1) * (px0 - px2) <= 0) && ((py0 - py1) * (py0 - py2) <= 0))
  33. {
  34. flag = true;
  35. }
  36. return flag;
  37. }
  38. //判断两线段相交
  39. bool IsIntersect(double px1, double py1, double px2, double py2, double px3, double py3, double px4, double py4)
  40. {
  41. bool flag = false;
  42. double d = (px2 - px1) * (py4 - py3) - (py2 - py1) * (px4 - px3);
  43. if (d != 0)
  44. {
  45. double r = ((py1 - py3) * (px4 - px3) - (px1 - px3) * (py4 - py3)) / d;
  46. double s = ((py1 - py3) * (px2 - px1) - (px1 - px3) * (py2 - py1)) / d;
  47. if ((r >= 0) && (r <= 1) && (s >= 0) && (s <= 1))
  48. {
  49. flag = true;
  50. }
  51. }
  52. return flag;
  53. }
  54. //判断点在多边形内
  55. bool Point_In_Polygon_2D(double x, double y, const vector<Vec2d> &POL)
  56. {
  57. bool isInside = false;
  58. int count = 0;
  59. //
  60. double minX = DBL_MAX;
  61. for (int i = 0; i < POL.size(); i++)
  62. {
  63. minX = std::min(minX, POL[i].x);
  64. }
  65. //
  66. double px = x;
  67. double py = y;
  68. double linePoint1x = x;
  69. double linePoint1y = y;
  70. double linePoint2x = minX -10; //取最小的X值还小的值作为射线的终点
  71. double linePoint2y = y;
  72. //遍历每一条边
  73. for (int i = 0; i < POL.size() - 1; i++)
  74. {
  75. double cx1 = POL[i].x;
  76. double cy1 = POL[i].y;
  77. double cx2 = POL[i + 1].x;
  78. double cy2 = POL[i + 1].y;
  79. if (IsPointOnLine(px, py, cx1, cy1, cx2, cy2))
  80. {
  81. return true;
  82. }
  83. if (fabs(cy2 - cy1) < EPSILON) //平行则不相交
  84. {
  85. continue;
  86. }
  87. if (IsPointOnLine(cx1, cy1, linePoint1x, linePoint1y, linePoint2x, linePoint2y))
  88. {
  89. if (cy1 > cy2) //只保证上端点+1
  90. {
  91. count++;
  92. }
  93. }
  94. else if (IsPointOnLine(cx2, cy2, linePoint1x, linePoint1y, linePoint2x, linePoint2y))
  95. {
  96. if (cy2 > cy1) //只保证上端点+1
  97. {
  98. count++;
  99. }
  100. }
  101. else if (IsIntersect(cx1, cy1, cx2, cy2, linePoint1x, linePoint1y, linePoint2x, linePoint2y)) //已经排除平行的情况
  102. {
  103. count++;
  104. }
  105. }
  106. if (count % 2 == 1)
  107. {
  108. isInside = true;
  109. }
  110. return isInside;
  111. }
  112. int main()
  113. {
  114. //定义一个多边形(六边形)
  115. vector<Vec2d> POL;
  116. POL.push_back(Vec2d(268.28, 784.75));
  117. POL.push_back(Vec2d(153.98, 600.60));
  118. POL.push_back(Vec2d(274.63, 336.02));
  119. POL.push_back(Vec2d(623.88, 401.64));
  120. POL.push_back(Vec2d(676.80, 634.47));
  121. POL.push_back(Vec2d(530.75, 822.85));
  122. POL.push_back(Vec2d(268.28, 784.75)); //将起始点放入尾部,方便遍历每一条边
  123. //
  124. if (Point_In_Polygon_2D(407.98, 579.43, POL))
  125. {
  126. cout << "点(407.98, 579.43)在多边形内" << endl;
  127. }
  128. else
  129. {
  130. cout << "点(407.98, 579.43)在多边形外" << endl;
  131. }
  132. //
  133. if (Point_In_Polygon_2D(678.92, 482.07, POL))
  134. {
  135. cout << "点(678.92, 482.07)在多边形内" << endl;
  136. }
  137. else
  138. {
  139. cout << "点(678.92, 482.07)在多边形外" << endl;
  140. }
  141. return 0;
  142. }

运行结果如下:

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. ES6语法的学习与实践

    ES6是JavaScript语言的新一代标准,是ECMAScript的第六个版本,加入了很多新的功能和语法,在很多框架,如在使用Vue,React等框架的项目中一般都采用ES6语法来编写的,下面对经常 ...

  2. Docker最全教程之使用TeamCity来完成内部CI、CD流程(十六)

    本篇教程主要讲解基于容器服务搭建TeamCity服务,并且完成内部项目的CI流程配置.教程中也分享了一个简单的CI.CD流程,仅作探讨.不过由于篇幅有限,完整的DevOps,我们后续独立探讨. 为了降 ...

  3. css常见的各种布局上(两列布局)

    常见的布局上(两列布局) 1.常见的两列布局 1.1左边固定,右边自适应,左边宽度已知,右边默认占满整行,使用left 左浮动,右边不浮动,设置margin-left:左侧宽度 <style&g ...

  4. Android之Fragment详解

    文章大纲 一. 什么是Fragment二. Fragment生命周期三. Fragment简单实例四.Fragment实战五.项目源码下载六.参考文章   一. 什么是Fragment Fragmen ...

  5. Soot生成代码控制流图

    Soot可以对代码进行分析,提供了多种字节码分析和变换功能,通过它可以进行过程内和过程间的分析优化,以及程序流图的生成,还能通过图形化的方式输出. http://www.brics.dk/SootGu ...

  6. Python之路【第二篇】:Python基础

    Python基础 对于Python,一切事物都是对象,对象基于类创建 所以,以下这些值都时对象:"zhurui".22.['北京','上海','深圳'],并且是根据不同的类生成的对 ...

  7. JDBC:SqlServer连接TCP/IP连接失败,到主机 的 TCP/IP 连接失败。报错信息:com.microsoft.sqlserver.jdbc.SQLServerException: 到主机 的 TCP/IP 连接失败。

    作者QQ:1161493927,欢迎互相交流学习. 报错信息:com.microsoft.sqlserver.jdbc.SQLServerException: 到主机 的 TCP/IP 连接失败. j ...

  8. 4.29 初始mysql

  9. GoLand2019 激活码

    此教程对最新2019版本GoLand有效!!! 本教程对windows.mac.ubuntu全系统可用 此教程实时更新,请放心使用:如果有新版本出现猪哥都会第一时间尝试激活: goland官网下载地址 ...

  10. mysql的学习笔记(三)

    1.外键约束(保持数据一致,完整.实现一对多或一对一) 父表(参照的表)和子表(有外键列的表)必须使用相同的存储引擎InnoDB,禁止使用临时表. 外键列和参照列必须具有相似的数据类型.其中数字的长度 ...