算法小白的第一次尝试---判断点是否在不规则区域范围内(手撕)

针对如何判断点是否在某一个不规则封闭区域内,主要采用的是向量积法,算法原理参考:

> https://blog.csdn.net/ezhchai/article/details/78864336?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

向量积计算参考:

> https://blog.csdn.net/qq_15906905/article/details/97074749?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

向量积法的核心是通过判断相邻边与待定点间的向量叉积(非点积)符号是否相同来判断,但该算法必须要求不规则多边形为凸多变形。但不规则多边形可以剖分成很多个三角形区域。因此,下面的function主要考虑的是三角形,该function针对叉积为0,待定点在边延长线上或在边上,均进行了处理:

  /**
    * 根据向量积法判断一个点是否在不规则区域范围内,向量积采用的方式为叉乘,非点乘
    * @param lon 经度,相当于x轴
    * @param lat 纬度,相当于y轴
    */
  def isInArea(lon: Double, lat: Double): Boolean = {
    //是否在区域范围内的标识
    var isIn = true
    //不规则区域顺时针各顶点座标
    val area = Array((113.517068, 22.938879), (114.86467, 23.291998), (114.149475, 21.972672))
    //顺时针方向各顶点连接成的向量
    val areaArea = new ArrayBuffer[(Double, Double)]()
    for (i <- 0 until (area.length - 1)) {
      areaArea.append((area(i + 1)._1 - area(i)._1, area(i + 1)._2 - area(i)._2))
    }
    areaArea.append((area.head._1 - area.last._1, area.head._2 - area.last._2))
    //待测点o与各顶点形成的向量
    val vector = new ArrayBuffer[(Double, Double)]()
    for (vertex <- area) {
      vector.append((lon - vertex._1, lat - vertex._2))
    }
    //依次计算待测点o与各顶点向量的向量积
    var vcp_pre = 0.0
    var flag = true
    for (i <- 0 until (area.length - 1) if flag) { //此处i只能取0,1
      vcp_pre = vector(i)._1 * areaArea(i)._2 - vector(i)._2 * areaArea(i)._1
      val vcp = vector(i + 1)._1 * areaArea(i + 1)._2 - vector(i + 1)._2 * areaArea(i + 1)._1
      val cp = vcp_pre * vcp
      if (cp == 0.0) {
        flag = false
        //此时应该判断该点是否在当前边的延长线上,若在延长线上则为false
        if (vcp_pre == 0.0) {
          if ((lon - area(i)._1) * (lon - area(i + 1)._1) > 0) isIn = false //判断是否在第一条边的延长线上
        } else {
          if (i < area.length - 2) {
            if ((lon - area(i + 1)._1) * (lon - area(i + 2)._1) > 0) isIn = false //判断是否在下一条边的延长线上
          } else {
            if ((lon - area.head._1) * (lon - area.last._1) > 0) isIn = false //判断是否在下一条边的延长线上
          }
        }
      } else if (cp < 0) { //前后相乘的结果必须为正,否则没有必要继续查找
        flag = false
        isIn = false
      }
    }
    isIn
  }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章