前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一种快速判断点在多边形内的算法

一种快速判断点在多边形内的算法

作者头像
sunsky
发布2022-09-08 15:08:45
9310
发布2022-09-08 15:08:45
举报
文章被收录于专栏:sunskysunsky

由于业务需要, 我总结了一种快速判断点在多边形内的算法。

先说思路:

如图:

  • 如果点在多边形内部,射线第一次穿越边界一定是穿出多边形。
  • 如果点在多边形外部,射线第一次穿越边界一定是进入多边形。

我们可以归纳出:

    • 当射线穿越多边形边界的次数为偶数时,所有第偶数次(包括最后一次)穿越都是穿出,因此所有第奇数次(包括第一次)穿越为穿入,由此可推断点在多边形外部。
    • 当射线穿越多边形边界的次数为奇数时,所有第奇数次(包括第一次和最后一次)穿越都是穿出,由此可推断点在多边形内部。

实现关键点

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是边的纵坐标。

问题都解决了,其实并不复杂。

实现代码

代码语言:javascript
复制
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
}
代码语言:javascript
复制
#压测
/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
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-07-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 先说思路:
  • 实现关键点
    • 1. 点在多边形的边上
      • 2. 点和多边形的顶点重合
        • 3. 射线经过多边形顶点
          • 4. 射线刚好经过一条边
          • 实现代码
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档