Glittering's blog Glittering's blog
Home
  • 学习手册

    • 《JavaScript教程》
    • 《ES6 教程》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
  • 技术文档
  • 算法
  • 工作总结
  • 实用技巧
  • collect
About
  • Classification
  • Label
GitHub (opens new window)

Glitz Ma

前端开发工程师
Home
  • 学习手册

    • 《JavaScript教程》
    • 《ES6 教程》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
  • 技术文档
  • 算法
  • 工作总结
  • 实用技巧
  • collect
About
  • Classification
  • Label
GitHub (opens new window)
  • 技术文档

  • 算法

  • 工作总结

    • 时区校正
    • 上传下载文件方式总结
    • webpack优化实践
    • webpack基础应用知识总结
    • vue常见原理总结
    • vue基础知识总结
    • react高级特性
    • react基础知识总结
    • 微前端总结
    • 今天总结一下用到的css吧
    • 地图标绘--射线法来计算点在多边形内
      • 射线法介绍
    • web异常监控和分析
    • 工作中遇到的css问题记录
    • axios 与 promise
    • 前端优化指南
    • 小程序笔记
    • JS随机打乱数组
    • 非常实用的JavaScript一行代码
  • 实用技巧

  • 收藏夹

  • 技术
  • 工作总结
mamingjuan
2020-02-22
目录

地图标绘--射线法来计算点在多边形内

# 射线法介绍

在地图应用上,我们会经常需要判断一个点是否位于多边形区域内,这里介绍下采用射线法如何实现。

算法思想:从待判断的点向某一个方向引射线,计算和多边形交点的个数,如果个数是偶数或者0,则点在多边形外,如果是奇数,则在多边形内,如下图: 这里有两种情况需要特殊处理:

  • 1) 射线经过顶点:当射线经过顶点时,判断就会出现异常情况。
  • 2) 点在边上:这种情况也不能用交点个数的奇偶性来判断了,要快速地判断这个点是否在边上:

GeoUtils.isPointInPolygon = (point, polygon)=> {
 if(!point || point.length<2) {
  console.error('坐标点格式错误')
  return false;
 }
 if(!polygon || polygon.length<4) {
  console.error('多边形格式错误')
  return false;
 }

 var pts = JSON.parse(JSON.stringify(polygon));
 // 下述代码来源:http://paulbourke.net/geometry/insidepoly/,进行了部分修改
 // 基本思想是利用射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则
 // 在多边形内。还会考虑一些特殊情况,如点在多边形顶点上,点在多边形边上等特殊情况。

 var boundOrVertex = true; // 如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
 var intersectCount = 0; // cross points count of x
 var precision = 2e-10; // 浮点类型计算时候与0比较时候的容差
 var p1, p2; // neighbour bound vertices
 var p = point; // 测试点
 var N = pts.length;

 p1 = pts[0]; //left vertex 左顶点
 for (var i = 1; i <= N; ++i) { // check all rays
  if (p.lat == p1.lat && p.lng ==p1.lng) { // 如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
   return boundOrVertex; // p is an vertex
  }

  p2 = pts[i % N]; // right vertex 右顶点
  // 如果判断点小于(p1、p2纬度最小) 或者 判断点 大于(p1、p2纬度最大) 如果全部不符合大于最小,小于最大的条件intersectCount = 0 没有处于内部
  if (p.lat < Math.min(p1.lat, p2.lat) || p.lat > Math.max(p1.lat, p2.lat)) { // ray is outside of our interests
   p1 = p2;
   continue; // next ray left point
  }

  // 如果纬度 大于最小并且小于最大,说明处于中间
  if (p.lat > Math.min(p1.lat, p2.lat) && p.lat < Math.max(p1.lat, p2.lat)) { // ray is crossing over by the algorithm (common part of)
   if (p.lng <= Math.max(p1.lng, p2.lng)) { //x is before of ray 经度小于p1、p2最大
    // 如果纬度p1、p2相等。并且 判断点 大于等于 最小的经度 (也就是说他们处于一条水平上)
    if (p1.lat == p2.lat && p.lng >= Math.min(p1.lng, p2.lng)) { // overlies on a horizontal ray
     return boundOrVertex;   
    }

    if (p1.lng == p2.lng) { // ray is vertical
     if (p1.lng == p.lng) { // overlies on a vertical ray 
      return boundOrVertex;
     } else { // before ray
      ++intersectCount;
     }
    } else { // cross point on the left side
     // 直线的斜率k=(y2-y1)/(x2-x1) 故直线方程为y-y1=(y2-y1)/(x2-x1)×(x-x1)
     var xinters = (p.lat - p1.lat) * (p2.lng - p1.lng) / (p2.lat - p1.lat) + p1.lng; // cross point of lng
     if (Math.abs(p.lng - xinters) < precision) { // overlies on a ray
      return boundOrVertex;
     }

     if (p.lng < xinters) { // before ray
      ++intersectCount;
     }
    }
   }
  } else { // special case when ray is crossing through the vertex
   if (p.lat == p2.lat && p.lng <= p2.lng) { //p crossing over p2
    var p3 = pts[(i + 1) % N]; //next vertex
    if (p.lat >= Math.min(p1.lat, p3.lat) && p.lat <= Math.max(p1.lat, p3.lat)) { //p.lat lies between p1.lat & p3.lat
     ++intersectCount; 
    } else {
     intersectCount += 2; 
    }
   }
  }
  p1 = p2; //next ray left point
 }

 if (intersectCount % 2 == 0) { // 偶数在多边形外
  return false;
 } else { // 奇数在多边形内
  return true;
 }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

参考文献 (opens new window)

上次更新: 2025/04/07, 01:42:58
今天总结一下用到的css吧
web异常监控和分析

← 今天总结一下用到的css吧 web异常监控和分析→

Copyright © 2015-2025 Glitz Ma
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式