一种快速判断点在多边形内的算法
2022/7/12 14:21:50
本文主要是介绍一种快速判断点在多边形内的算法,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
由于业务需要, 我总结了一种快速判断点在多边形内的算法。
先说思路:
如图:
- 如果点在多边形内部,射线第一次穿越边界一定是穿出多边形。
- 如果点在多边形外部,射线第一次穿越边界一定是进入多边形。
我们可以归纳出:
-
- 当射线穿越多边形边界的次数为偶数时,所有第偶数次(包括最后一次)穿越都是穿出,因此所有第奇数次(包括第一次)穿越为穿入,由此可推断点在多边形外部。
- 当射线穿越多边形边界的次数为奇数时,所有第奇数次(包括第一次和最后一次)穿越都是穿出,由此可推断点在多边形内部。
实现关键点
1. 点在多边形的边上
前面我们讲到,射线法的主要思路就是计算射线穿越多边形边界的次数。那么对于点在多边形的边上这种特殊情况,射线出发的这一次,是否应该算作穿越呢?
思路: 先求边和点的交点, 即边的起点y乘以边斜率,得到交点的x, 若x == X, X是参考点的横坐标,则点在线上。
2. 点和多边形的顶点重合
思路:参考点与边顶点重合,则直接是 x == X && y == Y ,其中x,y是边顶点, X,Y是参考点, 则直接返回。
3. 射线经过多边形顶点
思路:这时相交点次数无论内外都是偶数次,无法判断。不过,这里看射线两侧的边如果都在两侧时算作一次“穿过”,即 y == Y时, x1 > X 并且 x2 <= X (或 x1 < X 且 x2 > X),穿过数次加1 , 其中X,Y是参考点, x1,y1 , x2, y2是线段顶点。
4. 射线刚好经过一条边
思路: 这个最简单, 直接判断 y == Y,可以理解成穿过了这条边的2个顶点, Y是参考点的纵坐标, y是边的纵坐标。
问题都解决了,其实并不复杂。
实现代码
type Point struct { X float64 Y float64 } func IfPointsInPolygon(point Point, area []Point) bool { // 目标点的x, y坐标 x := point.X y := point.Y // 多边形的点数 count := len(area) // 点是否在多边形中 var inInside bool // 浮点类型计算与0的容差 precision := 2e-10 // 依次计算每条边,根据每边两端点和目标点的状态栏判断 for i, j := 0, count-1; i < count; j, i = i, i+1 { // 记录每条边上的两个点坐标 x1 := area[i].X y1 := area[i].Y x2 := area[j].X y2 := area[j].Y // 判断点与多边形顶点是否重合 if (x1 == x && y1 == y) || (x2 == x && y2 == y) { return true } // 判断点是否在水平直线上 if (y == y1) && (y == y2) { return true } // 判断线段两端点是否在射线两侧 if (y >= y1 && y < y2) || (y < y1 && y >= y2) { // 斜率 k := (x2 - x1) / (y2 - y1) // 相交点的 x 坐标 _x := x1 + k*(y-y1) // 点在多边形的边上 if _x == x { return true } // 浮点类型计算容差 if math.Abs(_x-x) < precision { return true } // 射线平行于x轴,穿过多边形的边 if _x > x { inInside = !inInside } } } return inInside }
#压测 /private/var/folders/9l/9h6c50j93qs8c43wpwnvhnbc0000gn/T/GoLand/___gobench_common_algorithm_polygon.test -test.v -test.paniconexit0 -test.bench . -test.run ^$ goos: darwin goarch: amd64 pkg: common/algorithm/polygon cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz BenchmarkPIP BenchmarkPIP-12 29140065 40.57 ns/op PASS
这篇关于一种快速判断点在多边形内的算法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南