scala 实现凸包算法

什么是凸包(Convex Hull)

请看维基百科

https://zh.wikipedia.org/wiki/凸包
简单的想,在二维平面,就是所有的点组成的最外层的凸多边形

算法思路

本文使用的方法是:包裹法(Jarvis步进法)

点在直线同一侧

点在直线两侧

从上面的两个图可以看到:

  1. 以凸包上相邻的两点连成的直线,所有的点都在该直线的同一侧
  2. 非凸包上的点连成的直线,所有的点分布在直线的两侧

算法实现

 /**
    * 凸包计算
    *
    * @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)

猜你喜欢

转载自blog.csdn.net/k_wzzc/article/details/82846866
今日推荐