根据经纬度来判断该位置是否属于任意区域内的点(区域可自定义,精确到街道)

需求:最近项目中遇到了这样一个需求,几千条含经纬度的数据,要根据位置将其按照街道分类(街道是比区小一级的行政单位)

先百度了,没有精确到街道一级边界集合,所以只能自己想办法获取各个街道的边界了

 

步骤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

 

 

 

 

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