需求:最近项目中遇到了这样一个需求,几千条含经纬度的数据,要根据位置将其按照街道分类(街道是比区小一级的行政单位)
先百度了,没有精确到街道一级边界集合,所以只能自己想办法获取各个街道的边界了
步骤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