需求:最近項目中遇到了這樣一個需求,幾千條含經緯度的數據,要根據位置將其按照街道分類(街道是比區小一級的行政單位)
先百度了,沒有精確到街道一級邊界集合,所以只能自己想辦法獲取各個街道的邊界了
步驟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