这个需求是在绘制地图过程中,通过经纬度边界绘制地图的点阵。有这么几个方法:

  • 射线法:从判断点向某个统一方向作射线,依交点个数的奇偶判断;
  • 转角法:按照多边形顶点逆时针顺序,根据顶点和判断点连线的方向正负(设定角度逆时针为正)求和判断;
  • 夹角和法:求判断点与所有边的夹角和,等于360度则在多边形内部。
  • 面积和法:求判断点与多边形边组成的三角形面积和,等于多边形面积则点在多边形内部。

比较下来面积计算比较复杂,角度计算开销比较大,射线法也要对每个边进行求交运算,但总体来说还是比其它方法好一些,下面就是最常用的射线法。

射线法

方法是从验证点向任意方向引一条射线,与多边形相交。计算射线与多边形的边的交点个数。

image.png
交点个数为奇数,则判断点在多边形内;偶数,则在多边形外。
但是,有这样的特殊情况:
image.png
因此定义了以下规则:

  • 射线与多边形的边重叠不计。
  • 相交点是边的上端点时不计。

这时:
a:与边6一个交点
b:与边4一个交点,与边3交点不计。
c:与边1、2交点不计,与边3一个交点。
d:与边4交点不计,与边5平行不计,与边6一个交点。

那么下面说说代码实现:(由于我获取的地理边界是PHP接口,下面用PHP说明,当然,翻译成别的语言也很容易)

  1. /*
  2. * @pt
  3. * @polys
  4. */
  5. function PointInPoly($pt, $polys) {
  6. $c = 0; //
  7. $l = count($polys); //
  8. $p1 = $polys[0];
  9. for ($i = 1; $i <= $l; $i++) {
  10. $p2 = $polys[$i]; // p1p2
  11. if ($pt[0] > min([$p1[0], $p2[0]])
  12. && $pt[0] <= max([$p1[0], $p2[0]])
  13. && $pt[1] <= max([$p1[1], $p2[1]])
  14. && $p1[0] != $p2[0]) {
  15. if ($p1[1] == $p2[1]) {
  16. $c++;
  17. } else {
  18. $x = ($pt[0] - $p1[0]) * ($p2[1] - $p1[1]) / ($p2[0] - $p1[0]) + $p1[1];
  19. if ($pt[1] <= $x) {
  20. $c++;
  21. }
  22. }
  23. }
  24. $p1 = $p2;
  25. }
  26. return $c % 2 != 0;
  27. }