给定经纬度定位某个城市

作者: siediyer 分类: Android 发布时间: 2017-10-16 12:01

方案1

通过GEO HASH,抓取每个格子里的点的地址信息,然后把这个地址信息作为GEO中点坐标的一个信息,当查询给定经纬度是在哪个城市的时候,查询过程是查询距离这个经纬度最近的带有地址的点,认为给定经纬度和最近的这个点是同一个地址下的。通过不断完善GEO中的每个坐标下的地址信息,可以提高整个系统的精度。这种方法相当于一种间接获取的方法的。

方案2

我们知道每个地区是有一定区域的,可以认为是一个闭合的多边形,定位城市,可以理解为判断某个点,是否在某个区域内。

第一点:如何获取城市的区域边界

很幸运的是百度地图提供了这样的API

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>获取地区轮廓线</title>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=1.3">
</script>
<style type="text/css">
body{font-size:13px;margin:10px}
#container{width:800px;height:500px;border:1px solid gray}
</style>
</head>
<body>
<div id="container"></div>
<br />
输入省、直辖市或县名称:<input type="text" id="districtName" style="width:80px" value="重庆市">
<input type="button" onclick="getBoundary()" value="获取轮廓线">

<script type="text/javascript">
var map = new BMap.Map("container");
map.centerAndZoom(new BMap.Point(116.403765, 39.914850), 5);
map.addControl(new BMap.NavigationControl({type: BMAP_NAVIGATION_CONTROL_SMALL}));
map.enableScrollWheelZoom();

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>
</body>
</html>

如果没有这样的API,我们也可以变相获得,大多数地图提供了通过经纬度获取地址信息的API,我们可以取一个城市内的一点,然后在城市外周围再取N个点,我们通过二分的方法,可以不断逼近边界

PHP代码

function border($city, $p1, $p2) {
    $tpl = 'http://api.map.baidu.com/geocoder/v2/?ak=你的应用key&callback=renderReverse&location=%s,%s&output=json&pois=1';
    $i = 5;
    while ($i>0) {
        $p1X = $p1[0];
        $p1Y = $p1[1];
        $p2X = $p2[0];
        $p2Y = $p2[1];
        $dX = abs($p1X - $p2X) / 2;
        $dY = abs($p1Y - $p2Y) / 2;
        $mX = min($p1X,$p2X) + $dX;
        $mY = min($p1Y,$p2Y) + $dY;

        $url = sprintf($tpl, $mY, $mX);
        $content = rtrim(strstr(file_get_contents($url), "{", false), ")");
        $data = json_decode($content, true);
        if (($data['result']['addressComponent']['city']) == $city) {
            $p1[0] = $mX;
            $p1[1] = $mY;
        } else {
            $p2[0] = $mX;
            $p2[1] = $mY;
        }
        $i--;
    }
    return array($p1[0],$p1[1]);
}

第二点:知道了区域,如何知道点在区域内

左边的图是从某个点向待检测的点引射线,右边的图是从待检测的点,向某个点引射线,这两种方法都可以,判断射线与闭合区域每条边相交的次数,如果是奇数次的话,可以判断点在区域内,如果是偶数次的话,可以判断点不在区域内。

 

实际编程中,第二种方法实现起来会更简单一些,而且我们都是向X轴的正方向引射线会更简单。

 

第三点:如何检测某个点正方向的射线和某条边相交

给定直线P1P2,判断点P平行于X轴正方的射线是否与直线P1P2相交?

首先,满足相交的条件,必须Py夹在P1y和P2y之间。

其次,满足相交的条件,Px小于P1P2最大x,不然肯定不想交了。

最后,P1,P2知道这两个点可以确定一条直线方程y=ax+b,然后p点正方的射线实际是y=Py的直线方程,这两条直线可以求出他们的焦点的x坐标xinters。如果Px小于xinters说明是在直线的y=ax+b的左边,向右引射线肯定能相交,如果Px大于xinters说明在y=ax+b的右边,向右引射线肯定不相交。

 

附上一段实现的代码

#define MIN(x,y) (x < y ? x : y)
#define MAX(x,y) (x > y ? x : y)
  
typedef struct {
   double x,y;
} Point;
  
int InsidePolygon(Point *polygon,int N,Point p)
{
  int counter = 0;
  int i;
  double xinters;
  Point p1,p2;
  
  p1 = polygon[0];
  for (i=1;i<=N;i++) {
    p2 = polygon[i % N];
    if (p.y > MIN(p1.y,p2.y)) { //低
      if (p.y <= MAX(p1.y,p2.y)) { //高
        if (p.x <= MAX(p1.x,p2.x)) { //右
          if (p1.y != p2.y) { //简单忽略平行X轴这种情况
            xinters = (p.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x; //交叉点坐标 参考./media/point-and-polygon/xinters.jpg
            if (p1.x == p2.x || p.x <= xinters)
              counter++;
          }
        }
      }
    }
    p1 = p2;
  }
  
  if (counter % 2 == 0)
    return 0;
  else
    return 1;
}

第四:幸运的是JAVA中的awt.Polygon已经实现了类似的算法

以下代码判断了一个经纬度是否在北京范围内

import java.awt.*;

public class Main {

    public static void init(Polygon p) {
        String s = "117.396814, 40.233095;117.360068, 40.242128;117.348757, 40.25027;117.343034, 40.283717;117.30242, 40.284012;117.300909, 40.298824;117.294971, 40.307248;117.280908, 40.31483;117.277872, 40.331475;117.281586, 40.338248;117.268763, 40.343838;117.248206, 40.376793;117.233105, 40.375358;117.230104, 40.381682;117.235062, 40.392322;117.241661, 40.395752;117.243127, 40.400548;117.246722, 40.40068;117.24604, 40.405045;117.238857, 40.410209;117.240581, 40.42306;117.256385, 40.435421;117.263364, 40.436067;117.26993, 40.447321;117.241196, 40.464298;117.242267, 40.475311;117.232341, 40.484311;117.234676, 40.48752;117.223574, 40.501212;117.215835, 40.502724;117.21653, 40.512643;117.220225, 40.518656;117.239555, 40.519506;117.245336, 40.523751;117.253813, 40.518445;117.266702, 40.525486;117.256848, 40.54366;117.259649, 40.547985;117.256124, 40.554638;117.272602, 40.564079;117.302711, 40.572713;117.317146, 40.582207;117.340905, 40.582418;117.356706, 40.586185;117.372601, 40.582034;117.382658, 40.572888;117.395929, 40.567374;117.410574, 40.579774;117.426571, 40.574504;117.436606, 40.584657;117.42995, 40.58783;117.420328, 40.612091;117.429118, 40.643382;117.478347, 40.653361;117.485398, 40.64184;117.507621, 40.642461;117.509516, 40.659031;117.513171, 40.660949;117.512283, 40.673448;117.501618, 40.68091;117.486462, 40.683865;117.471233, 40.679811;117.427458, 40.691901;117.413032, 40.691963;117.368422, 40.681015;117.352677, 40.680053;117.343188, 40.672822;117.343163, 40.669474;117.332062, 40.666479;117.298595, 40.665641;117.284975, 40.672219;117.267992, 40.687306;117.248559, 40.682887;117.237938, 40.691027;117.21279, 40.700633;117.189813, 40.703272;117.185509, 40.699216;117.173492, 40.704884;117.159189, 40.703082;117.123309, 40.706232;117.11851, 40.713341;117.090641, 40.708002;117.056273, 40.706007;117.037346, 40.698128;117.010825, 40.702995;116.971399, 40.715332;116.972824, 40.719631;116.951579, 40.733725;116.947612, 40.745358;116.933105, 40.750454;116.929846, 40.757856;116.934815, 40.762214;116.930179, 40.779446;116.904581, 40.783162;116.901081, 40.788008;116.9026, 40.800071;116.88808, 40.809295;116.888235, 40.820112;116.881718, 40.827765;116.867501, 40.831665;116.862506, 40.841264;116.844057, 40.847245;116.829961, 40.848436;116.827445, 40.853933;116.819235, 40.853821;116.812193, 40.846273;116.80869, 40.85693;116.789081, 40.879637;116.77733, 40.887135;116.764859, 40.889985;116.765735, 40.896678;116.743541, 40.903681;116.737051, 40.903223;116.732415, 40.909594;116.720191, 40.915779;116.722334, 40.924405;116.73105, 40.935302;116.724433, 40.941791;116.712821, 40.939941;116.697791, 40.956023;116.693814, 40.967528;116.684172, 40.977679;116.684106, 40.982014;116.691199, 40.988235;116.691729, 41.007364;116.698209, 41.014096;116.697524, 41.018573;116.702854, 41.021883;116.704409, 41.031402;116.696054, 41.050272;116.690283, 41.047187;116.665317, 41.056873;116.655365, 41.063919;116.637532, 41.066884;116.632524, 41.061892;116.622608, 41.059055;116.624713, 41.054896;116.620421, 41.04299;116.628376, 41.0337;116.62829, 41.022061;116.622062, 41.0105;116.621672, 40.992318;116.606371, 40.981254;116.592437, 40.985128;116.580618, 40.993771;116.566631, 40.998804;116.56466, 40.994409;116.554092, 40.993979;116.547776, 40.996659;116.525911, 40.987794;116.523141, 40.981751;116.499718, 40.984453;116.492126, 40.988346;116.480946, 40.983933;116.470491, 40.990227;116.462585, 40.984177;116.454523, 40.960213;116.468624, 40.938999;116.474211, 40.93707;116.481905, 40.917902;116.483361, 40.905498;116.480853, 40.903074;116.443685, 40.90498;116.437039, 40.909232;116.421842, 40.906839;116.408434, 40.911863;116.398376, 40.92057;116.377851, 40.949215;116.372863, 40.949316;116.366048, 40.941941;116.347659, 40.936639;116.341021, 40.9254;116.340967, 40.91152;116.388424, 40.869752;116.396076, 40.868438;116.397954, 40.861524;116.411794, 40.847151;116.412806, 40.839748;116.444768, 40.824186;116.449148, 40.812842;116.458652, 40.803974;116.465447, 40.802591;116.472163, 40.77826;116.460539, 40.771806;116.445402, 40.772914;116.422367, 40.768351;116.416833, 40.785757;116.401677, 40.78488;116.373736, 40.776837;116.328394, 40.778196;116.320514, 40.77693;116.314111, 40.769582;116.317666, 40.760475;116.314075, 40.758484;116.294132, 40.770103;116.280562, 40.769739;116.275753, 40.781289;116.254416, 40.797832;116.241679, 40.789088;116.242438, 40.781394;116.236838, 40.768522;116.240245, 40.764807;116.221101, 40.750547;116.219936, 40.746062;116.226137, 40.739108;116.216877, 40.727078;116.209974, 40.72149;116.193057, 40.724782;116.18734, 40.718765;116.177616, 40.702363;116.180134, 40.699151;116.171808, 40.674123;116.164609, 40.669972;116.148927, 40.673475;116.138716, 40.661807;116.120445, 40.654743;116.118173, 40.649776;116.126964, 40.631189;116.117788, 40.62193;116.068027, 40.615224;116.037281, 40.603575;116.026374, 40.604705;116.01256, 40.594188;116.00943, 40.581671;115.988979, 40.584777;115.979101, 40.607208;115.96029, 40.607401;115.950341, 40.617487;115.934286, 40.619091;115.916134, 40.624756;115.894762, 40.602501;115.834129, 40.593641;115.82805, 40.569572;115.820068, 40.563255;115.805593, 40.563806;115.797891, 40.567662;115.767764, 40.545073;115.761164, 40.545717;115.742637, 40.510394;115.752305, 40.498003;115.783837, 40.492361;115.775733, 40.468534;115.778708, 40.455699;115.788186, 40.444804;115.803563, 40.436957;115.811505, 40.426348;115.824703, 40.392614;115.839213, 40.384772;115.855604, 40.38265;115.87134, 40.368466;115.882848, 40.364071;115.895453, 40.367279;115.910131, 40.366321;115.91565, 40.373277;115.92271, 40.373176;115.930506, 40.348471;115.929014, 40.342954;115.93938, 40.324907;115.949202, 40.320196;115.950679, 40.31592;115.946689, 40.310072;115.952985, 40.294974;115.95687, 40.293726;115.962316, 40.28308;115.967807, 40.28117;115.967703, 40.276763;115.974803, 40.269453;115.96956, 40.263582;115.939616, 40.261757;115.925633, 40.254556;115.917889, 40.241488;115.905256, 40.241696;115.890773, 40.22004;115.894544, 40.215076;115.878751, 40.193072;115.86747, 40.19034;115.850978, 40.173889;115.859884, 40.154416;115.813286, 40.159262;115.800328, 40.174545;115.796151, 40.18475;115.779416, 40.182207;115.774742, 40.172296;115.763447, 40.169641;115.756972, 40.159365;115.761798, 40.150631;115.754547, 40.140404;115.731648, 40.134635;115.693943, 40.144939;115.661502, 40.133591;115.657429, 40.123404;115.618554, 40.122766;115.61325, 40.120591;115.61212, 40.109824;115.607844, 40.10545;115.610083, 40.099374;115.587407, 40.101838;115.582502, 40.108779;115.559105, 40.087639;115.549021, 40.082009;115.534603, 40.082349;115.516148, 40.071128;115.513656, 40.063479;115.49734, 40.056354;115.479551, 40.039915;115.462648, 40.033699;115.459211, 40.029466;115.454533, 39.999598;115.450072, 40.000977;115.440883, 39.995542;115.43257, 39.985449;115.430282, 39.961629;115.433244, 39.956319;115.448393, 39.958579;115.482655, 39.943021;115.496416, 39.927586;115.513516, 39.919226;115.527724, 39.907377;115.529448, 39.904259;115.51576, 39.889913;115.517443, 39.886911;115.535997, 39.882121;115.530323, 39.874847;115.527983, 39.86375;115.517405, 39.850512;115.532551, 39.836925;115.551154, 39.832822;115.575643, 39.819741;115.57307, 39.811205;115.558665, 39.801297;115.550738, 39.802418;115.519505, 39.794138;115.513357, 39.788984;115.498847, 39.802132;115.490144, 39.804462;115.466597, 39.789538;115.446208, 39.789696;115.443016, 39.782414;115.4537, 39.755596;115.475508, 39.746881;115.489207, 39.748202;115.498946, 39.744467;115.494841, 39.737957;115.498926, 39.707306;115.506367, 39.69717;115.495458, 39.687104;115.49821, 39.674617;115.485294, 39.661638;115.485203, 39.656314;115.513505, 39.65776;115.522393, 39.648146;115.528856, 39.645963;115.525992, 39.618943;115.539326, 39.617612;115.552049, 39.625147;115.575098, 39.604458;115.580881, 39.602542;115.57802, 39.598252;115.580937, 39.597404;115.592675, 39.595736;115.606081, 39.605443;115.624996, 39.609891;115.640839, 39.603874;115.640124, 39.60979;115.648167, 39.609304;115.650382, 39.605047;115.664199, 39.607415;115.677061, 39.614593;115.687469, 39.602859;115.6977, 39.597042;115.700636, 39.58446;115.698616, 39.572297;115.724345, 39.567191;115.733957, 39.55403;115.744881, 39.549176;115.750469, 39.530171;115.758146, 39.518671;115.769417, 39.52097;115.774597, 39.513389;115.77468, 39.521173;115.803517, 39.516067;115.833646, 39.518631;115.834908, 39.547445;115.852755, 39.549069;115.853237, 39.557078;115.859607, 39.558462;115.872222, 39.553433;115.893877, 39.55684;115.893426, 39.562061;115.89959, 39.562647;115.900299, 39.57279;115.914709, 39.575423;115.918661, 39.579418;115.92096, 39.5894;115.91514, 39.59102;115.913687, 39.602606;115.919764, 39.605797;115.927621, 39.603682;115.927525, 39.600123;115.93517, 39.59979;115.936548, 39.590961;115.950787, 39.582123;115.956732, 39.572271;115.964618, 39.57154;115.983172, 39.576154;115.983491, 39.600071;115.991092, 39.600501;115.998195, 39.599442;115.999942, 39.589146;116.003687, 39.588679;116.001695, 39.582687;116.014635, 39.583917;116.022136, 39.593854;116.043035, 39.57876;116.07333, 39.577713;116.110362, 39.580779;116.111984, 39.576795;116.153802, 39.575452;116.16104, 39.586423;116.200314, 39.588234;116.207352, 39.58384;116.227953, 39.584402;116.245105, 39.556047;116.250727, 39.552413;116.251984, 39.521643;116.258316, 39.516687;116.261105, 39.50889;116.282528, 39.501232;116.285552, 39.497833;116.310498, 39.493163;116.325583, 39.480138;116.332267, 39.468477;116.349029, 39.458592;116.351422, 39.453985;116.371229, 39.453886;116.372291, 39.457582;116.383324, 39.459122;116.394203, 39.456088;116.399532, 39.458963;116.425853, 39.454582;116.436799, 39.445587;116.444783, 39.448582;116.448654, 39.447369;116.458375, 39.453186;116.462321, 39.46309;116.456546, 39.468347;116.454885, 39.482176;116.44748, 39.492161;116.427339, 39.502878;116.413425, 39.529626;116.425291, 39.528906;116.432281, 39.522346;116.441316, 39.522359;116.446318, 39.524486;116.449053, 39.535027;116.483584, 39.545471;116.484288, 39.555351;116.51236, 39.561538;116.533535, 39.579411;116.530868, 39.603113;116.561077, 39.604456;116.575397, 39.60992;116.574035, 39.615511;116.578352, 39.625892;116.597606, 39.62995;116.608882, 39.627922;116.60958, 39.617675;116.618347, 39.614326;116.63956, 39.598435;116.649575, 39.602253;116.65341, 39.612935;116.701393, 39.602494;116.710341, 39.59463;116.735224, 39.599557;116.712803, 39.615639;116.712707, 39.620278;116.732272, 39.622677;116.770397, 39.621126;116.781618, 39.611405;116.786732, 39.600158;116.794329, 39.602738;116.792869, 39.609761;116.798272, 39.610925;116.798806, 39.616774;116.835365, 39.623318;116.847796, 39.629981;116.837352, 39.642124;116.837919, 39.648702;116.857622, 39.661133;116.858348, 39.670383;116.862345, 39.673679;116.890055, 39.681869;116.899041, 39.67916;116.913065, 39.682652;116.912129, 39.692889;116.895367, 39.709769;116.889375, 39.722799;116.896226, 39.731878;116.905895, 39.732316;116.918338, 39.737685;116.915713, 39.755851;116.905956, 39.765245;116.917067, 39.769397;116.926504, 39.785708;116.954922, 39.787312;116.958916, 39.788953;116.957802, 39.793369;116.947889, 39.802187;116.942966, 39.801267;116.941163, 39.807497;116.944047, 39.811272;116.934897, 39.8194;116.934864, 39.836027;116.921582, 39.8546;116.914208, 39.858458;116.910419, 39.856768;116.908704, 39.849417;116.914744, 39.836888;116.906097, 39.838156;116.892248, 39.85166;116.865868, 39.864936;116.858785, 39.876295;116.826594, 39.895721;116.810909, 39.894968;116.798184, 39.891052;116.790891, 39.904278;116.787847, 39.924116;116.790425, 39.947352;116.784383, 39.957745;116.785533, 39.962352;116.781118, 39.966493;116.778104, 39.962551;116.768888, 39.965436;116.766651, 39.963757;116.763082, 39.967772;116.774479, 39.991807;116.782163, 39.999264;116.777743, 40.020054;116.79169, 40.04063;116.808115, 40.035326;116.812623, 40.039475;116.829879, 40.034153;116.830104, 40.053132;116.856134, 40.058213;116.856655, 40.06071;116.862424, 40.059915;116.879125, 40.046781;116.887003, 40.052001;116.897445, 40.05203;116.91645, 40.058756;116.921103, 40.058581;116.924633, 40.052961;116.929155, 40.052608;116.937167, 40.060357;116.945078, 40.053844;116.949071, 40.054797;116.953609, 40.047448;116.968858, 40.057487;116.97638, 40.054388;116.979592, 40.047527;116.9842, 40.045447;117.01239, 40.038834;117.03162, 40.038702;117.045767, 40.055848;117.060658, 40.061359;117.062142, 40.064898;117.088476, 40.070829;117.095952, 40.076216;117.119763, 40.078627;117.142575, 40.070338;117.16233, 40.075069;117.167983, 40.081988;117.183281, 40.07842;117.191574, 40.091165;117.219451, 40.102784;117.230842, 40.100735;117.230798, 40.104818;117.256558, 40.125811;117.264635, 40.118738;117.282491, 40.119351;117.294419, 40.127966;117.305696, 40.128324;117.318401, 40.145199;117.351763, 40.148592;117.364739, 40.166702;117.360039, 40.179331;117.371849, 40.184583;117.39733, 40.184087;117.411835, 40.190451;117.413853, 40.193758;117.410394, 40.194931;117.402432, 40.192313;117.386786, 40.198355;117.387165, 40.205991;117.394824, 40.209093;117.395258, 40.212225;117.385567, 40.214483;117.38483, 40.223684;117.399491, 40.227136;117.396814, 40.233095";
        for ( String t : s.split(";")) {
            int x = (int) (Float.parseFloat(t.split(",")[0]) * 1000);
            int y = (int) (Float.parseFloat(t.split(",")[1]) * 1000);
            p.addPoint(x, y);
        }
    }

    public static boolean contains(Polygon p, float x, float y) {
        return p.contains(x * 1000, y * 1000);
    }

    public static void main(String[] args) {
        Polygon p = new Polygon();
        init(p);
        contains(p, 116.270313f, 39.909622f);
        contains(p, 115.590763f, 40.032598f);
        contains(p, 115.903517f ,40.875831f);
    }
}

 

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

Title - Artist
0:00