根據經緯度來判斷該位置是否屬於任意區域內的點(區域可自定義,精確到街道)

需求:最近項目中遇到了這樣一個需求,幾千條含經緯度的數據,要根據位置將其按照街道分類(街道是比區小一級的行政單位)

先百度了,沒有精確到街道一級邊界集合,所以只能自己想辦法獲取各個街道的邊界了

 

步驟1:先獲取邊界點的集合

                                      

<body>
<div style="width:920px;height:440px;border:1px solid gray" id="container"></div>
<p><input id="startBtn" type="button" onclick="startTool();" value="開啓取點工具" /><input type="button" onclick="map.clearOverlays();document.getElementById('info').innerHTML = '';points=[];" value="清除" /></p>

輸入省、直轄市或縣名稱:<input type="text" id="districtName" style="width:80px" value="XX區">
<input type="button" onclick="getBoundary()" value="獲取輪廓線">

<div id="info"></div>
</body>
</html>
<script type="text/javascript">
var map = new BMap.Map("container");                        // 創建Map實例
map.centerAndZoom("北京", 11);     // 初始化地圖,設置中心點座標和地圖級別
map.addControl(new BMap.NavigationControl({type: BMAP_NAVIGATION_CONTROL_SMALL}));
map.enableScrollWheelZoom();

var key = 1;    //開關
var newpoint;   //一個經緯度
var points = [];    //數組,放經緯度信息
var polyline = new BMap.Polyline(); //折線覆蓋物

function startTool(){   //開關函數
if(key==1){
        document.getElementById("startBtn").style.background = "green";
        document.getElementById("startBtn").style.color = "white";
        document.getElementById("startBtn").value = "開啓狀態";
        key=0;
    }
    else{
        document.getElementById("startBtn").style.background = "red";
        document.getElementById("startBtn").value = "關閉狀態";
        key=1;
    }
}
map.addEventListener("click",function(e){   //單擊地圖,形成折線覆蓋物
    newpoint = new BMap.Point(e.point.lng,e.point.lat);
    if(key==0){
    //    if(points[points.length].lng==points[points.length-1].lng){alert(111);}
        points.push(newpoint);  //將新增的點放到數組中
        polyline.setPath(points);   //設置折線的點數組
        map.addOverlay(polyline);   //將折線添加到地圖上
        document.getElementById("info").innerHTML += "new BMap.Point(" + e.point.lng + "," + e.point.lat + "),</br>";    //輸出數組裏的經緯度
    }
});
map.addEventListener("dblclick",function(e){   //雙擊地圖,形成多邊形覆蓋物
if(key==0){
        map.disableDoubleClickZoom();   //關閉雙擊放大
var polygon = new BMap.Polygon(points);
        map.addOverlay(polygon);   //將折線添加到地圖上
    }
});


function getBoundary(){       
    var bdary = new BMap.Boundary();
    var name = document.getElementById("districtName").value;
    bdary.get(name, function(rs){       //獲取行政區域
        map.clearOverlays();        //清除地圖覆蓋物       
        var count = rs.boundaries.length; //行政區域的點有多少個
        for(var i = 0; i < count; i++){
            var ply = new BMap.Polygon(rs.boundaries[i], {strokeWeight: 2, strokeColor: "#ff0000"}); //建立多邊形覆蓋物
            map.addOverlay(ply);  //添加覆蓋物
            map.setViewport(ply.getPath());    //調整視野         
        }                
    });   
}
</script>

1.先在“輸入省、直轄市或縣名稱”的框中輸入區,勾畫出區級行政區域的邊界圖,再點擊“開啓狀態”手動根據該區級單位的各個街道劃分界限,將各個街道邊界點描畫出來,描點時可以放大地圖,儘可能多打點,最後形成一個封閉的多邊形。如果最後封閉的點打點有誤差,可以手動將第一個點的經緯度與最後一個點的經緯度改成一致。(忽略下圖中其他的混亂的線,是測試時點的)

         

2.將下面的獲取到的街道邊界點按照不同的街道分類,保存下來。

                             

步驟二:將數據庫中的經緯度,放入邊界點集合中比對

 建立封裝緯度的實體類

public class Point {

    private Double x;  
     private Double y;  
     public Point (Double x , Double y) {  
         this.x = x;  
         this.y = y;  
     }  
     public Double getX() {  
         return x;  
     }  
     public void setX(Double x) {  
         this.x = x;  
     }  
     public Double getY() {  
         return y;  
     }  
     public void setY(Double y) {  
         this.y = y;  
     }      
}

將街道邊界點放入point對象數組中

 

判斷點是否在某邊界線範圍內:

 public static boolean isPtInPoly (double ALon , double ALat , Point[] ps) {  
       int iSum, iCount, iIndex;  
       double dLon1 = 0, dLon2 = 0, dLat1 = 0, dLat2 = 0, dLon;  
       if (ps.length < 3) {  
           return false;  
       }  
       iSum = 0;  
       iCount = ps.length;  
       for (iIndex = 0; iIndex<iCount;iIndex++) {  
           if (iIndex == iCount - 1) {  
               dLon1 = ps[iIndex].getX();  
               dLat1 = ps[iIndex].getY();  
               dLon2 = ps[0].getX();  
               dLat2 = ps[0].getY();  
           } else {  
               dLon1 = ps[iIndex].getX();  
               dLat1 = ps[iIndex].getY();  
               dLon2 = ps[iIndex + 1].getX();  
               dLat2 = ps[iIndex + 1].getY();  
           }  
           // 以下語句判斷A點是否在邊的兩端點的水平平行線之間,在則可能有交點,開始判斷交點是否在左射線上  
           if (((ALat >= dLat1) && (ALat < dLat2)) || ((ALat >= dLat2) && (ALat < dLat1))) {  
               if (Math.abs(dLat1 - dLat2) > 0) {  
                   //得到 A點向左射線與邊的交點的x座標:  
                   dLon = dLon1 - ((dLon1 - dLon2) * (dLat1 - ALat) ) / (dLat1 - dLat2);  
                   // 如果交點在A點左側(說明是做射線與 邊的交點),則射線與邊的全部交點數加一:  
                   if (dLon < ALon) {  
                       iSum++;  
                   }  
               }  
           }  
       }  
       if ((iSum % 2) != 0) {  
           return true;  
       }  
       return false;  
   }  

測試:

boolean ptInPoly = isPtInPoly(114.19216612023824,30.62299719226428,new StreetsLocations().getYijiajie());

 自己測試了部分值驗證了一下,判斷部分還是比較準確的,誤差點在於手動點邊界線時的誤差,如果項目不能接受這種誤差的話,就要另尋他法了~

相關代碼的下載: https://download.csdn.net/download/qq_42431881/11941606

 

 

 

 

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