算法小白的第一次嘗試---判斷點是否在不規則區域範圍內(手撕)

針對如何判斷點是否在某一個不規則封閉區域內,主要採用的是向量積法,算法原理參考:

> 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
  }

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