什么是凸包(Convex Hull)
请看维基百科
https://zh.wikipedia.org/wiki/凸包
简单的想,在二维平面,就是所有的点组成的最外层的凸多边形
算法思路
本文使用的方法是:包裹法(Jarvis步进法)
从上面的两个图可以看到:
- 以凸包上相邻的两点连成的直线,所有的点都在该直线的同一侧
- 非凸包上的点连成的直线,所有的点分布在直线的两侧
算法实现
/**
* 凸包计算
*
* @param pts
* @return
*/
def convexHull(pts: List[Point]) = {
// 前置条件 计算凸包的点集数量要大于2
require(pts.size > 2)
var pset = Set[Point]()
val loop = new Breaks
// 遍历所有的点集组合
for (i <- 0 until pts.size - 1; j <- i + 1 until pts.size) {
var set = Set[Boolean]()
// 取两点科构建一条直线
val p1 = pts(i); val p2 = pts(j)
loop.breakable {
//遍历所有的点 判断点是否在直线同一侧
for (p <- pts) {
if (((p.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x) < p.x) {
set += false
if (set.size != 1) loop.break()
} else {
set += true
if (set.size != 1) loop.break()
}
}
}
if (set.size == 1) {
pset += p1
pset += p2
}
}
pset.toList
}
我们以上图的点为例就算该点集的凸包
val list2 = List(Point(0, 0), Point(2, 0), Point(2, 2), Point(0, 2),
Point(1, 1), Point(2, 4), Point(1, 3),Point(1,2))
convexHull(list2).foreach(println)
得结果和实际一致,我们可以看到点C,在直线BD之上,这个点可以作为凸包的点,也可以不作为凸包的点。
Point(0.0,0.0)
Point(2.0,0.0)
Point(2.0,2.0)
Point(2.0,4.0)