文档章节

关于计算周围多少里以内的楼盘

沉淀岁月
 沉淀岁月
发布于 2015/07/18 00:02
字数 1263
阅读 9
收藏 0
/**
     * 根据经纬度计算距离 其中A($lat1,$lng1)、B($lat2,$lng2)
         * 注意弧度角度的计算
     * 单位:km
     */
    function _getDistance($lat1,$lng1,$lat2,$lng2)
    {
        //地球半径
        $R = 6378.137; //km
    
        //将角度转为狐度
        $radLat1 = deg2rad($lat1);
        $radLat2 = deg2rad($lat2);
        $radLng1 = deg2rad($lng1);
        $radLng2 = deg2rad($lng2);
    
        //结果
        $s = acos(cos($radLat1)*cos($radLat2)*cos($radLng1-$radLng2)+sin($radLat1)*sin($radLat2))*$R;
    
        //精度
        $s = round($s* 10000)/10000;
        return  round($s);
    }
/**
 *根据传入的中心点的经纬度和半径,计算出矩形区域
 * @param float $center_lat
 * @param float $center_lng
 * @param int   $radius unit:km
 */
function getAroundRectangle($center_lat, $center_lng, $radius)
{
    //先来求东西两侧的的范围边界 经度
    $earth_radius = 6378.137;    //km
    $dlng = rad2deg(2 * asin(sin($radius / (2 * $earth_radius)) / cos(deg2rad($center_lat)))); //角度
     
    //然后求南北两侧的范围边界 维度
    $dlat = rad2deg($radius/$earth_radius);
    
    $data = array(
        'lat_min' => $center_lat-$dlat,//维度最小
        'lat_max' => $center_lat+$dlat,//唯独 最大
        'lng_min' => $center_lng-$dlng,//经度最小
        'lng_max' => $center_lng+$dlng,//经度最大
    );
    return $data;
}
/**
 * Geohash generation class
 * http://blog.dixo.net/downloads/
 *
 * This file copyright (C) 2008 Paul Dixon (paul@elphin.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */



/**
* Encode and decode geohashes
*
*/
class Geohash
{
    private $coding="0123456789bcdefghjkmnpqrstuvwxyz";
    private $codingMap=array();
    
    public function Geohash()
    {
        //build map from encoding char to 0 padded bitfield
        for($i=0; $i<32; $i++)
        {
            $this->codingMap[substr($this->coding,$i,1)]=str_pad(decbin($i), 5, "0", STR_PAD_LEFT);
        }
        
    }
    
    /**
    * Decode a geohash and return an array with decimal lat,long in it
    */
    public function decode($hash)
    {
        //decode hash into binary string
        $binary="";
        $hl=strlen($hash);
        for($i=0; $i<$hl; $i++)
        {
            $binary.=$this->codingMap[substr($hash,$i,1)];
        }
        
        //split the binary into lat and log binary strings
        $bl=strlen($binary);
        $blat="";
        $blong="";
        for ($i=0; $i<$bl; $i++)
        {
            if ($i%2)
                $blat=$blat.substr($binary,$i,1);
            else
                $blong=$blong.substr($binary,$i,1);
            
        }
        
        //now concert to decimal
        $lat=$this->binDecode($blat,-90,90);
        $long=$this->binDecode($blong,-180,180);
        
        //figure out how precise the bit count makes this calculation
        $latErr=$this->calcError(strlen($blat),-90,90);
        $longErr=$this->calcError(strlen($blong),-180,180);
                
        //how many decimal places should we use? There's a little art to
        //this to ensure I get the same roundings as geohash.org
        $latPlaces=max(1, -round(log10($latErr))) - 1;
        $longPlaces=max(1, -round(log10($longErr))) - 1;
        
        //round it
        $lat=round($lat, $latPlaces);
        $long=round($long, $longPlaces);
        
        return array($lat,$long);
    }

    
    /**
    * Encode a hash from given lat and long
    */
    public function encode($lat,$long)
    {
        //how many bits does latitude need?    
        $plat=$this->precision($lat);
        $latbits=1;
        $err=45;
        while($err>$plat)
        {
            $latbits++;
            $err/=2;
        }
        
        //how many bits does longitude need?
        $plong=$this->precision($long);
        $longbits=1;
        $err=90;
        while($err>$plong)
        {
            $longbits++;
            $err/=2;
        }
        
        //bit counts need to be equal
        $bits=max($latbits,$longbits);
        
        //as the hash create bits in groups of 5, lets not
        //waste any bits - lets bulk it up to a multiple of 5
        //and favour the longitude for any odd bits
        $longbits=$bits;
        $latbits=$bits;
        $addlong=1;
        while (($longbits+$latbits)%5 != 0)
        {
            $longbits+=$addlong;
            $latbits+=!$addlong;
            $addlong=!$addlong;
        }
        
        
        //encode each as binary string
        $blat=$this->binEncode($lat,-90,90, $latbits);
        $blong=$this->binEncode($long,-180,180,$longbits);
        
        //merge lat and long together
        $binary="";
        $uselong=1;
        while (strlen($blat)+strlen($blong))
        {
            if ($uselong)
            {
                $binary=$binary.substr($blong,0,1);
                $blong=substr($blong,1);
            }
            else
            {
                $binary=$binary.substr($blat,0,1);
                $blat=substr($blat,1);
            }
            $uselong=!$uselong;
        }
        
        //convert binary string to hash
        $hash="";
        for ($i=0; $i<strlen($binary); $i+=5)
        {
            $n=bindec(substr($binary,$i,5));
            $hash=$hash.$this->coding[$n];
        }
        
        
        return $hash;
    }
    
    /**
    * What's the maximum error for $bits bits covering a range $min to $max
    */
    private function calcError($bits,$min,$max)
    {
        $err=($max-$min)/2;
        while ($bits--)
            $err/=2;
        return $err;
    }
    
    /*
    * returns precision of number
    * precision of 42 is 0.5
    * precision of 42.4 is 0.05
    * precision of 42.41 is 0.005 etc
    */
    private function precision($number)
    {
        $precision=0;
        $pt=strpos($number,'.');
        if ($pt!==false)
        {
            $precision=-(strlen($number)-$pt-1);
        }
        
        return pow(10,$precision)/2;
    }
    
    
    /**
    * create binary encoding of number as detailed in http://en.wikipedia.org/wiki/Geohash#Example
    * removing the tail recursion is left an exercise for the reader
    */
    private function binEncode($number, $min, $max, $bitcount)
    {
        if ($bitcount==0)
            return "";
        
        #echo "$bitcount: $min $max<br>";
            
        //this is our mid point - we will produce a bit to say
        //whether $number is above or below this mid point
        $mid=($min+$max)/2;
        if ($number>$mid)
            return "1".$this->binEncode($number, $mid, $max,$bitcount-1);
        else
            return "0".$this->binEncode($number, $min, $mid,$bitcount-1);
    }
    

    /**
    * decodes binary encoding of number as detailed in http://en.wikipedia.org/wiki/Geohash#Example
    * removing the tail recursion is left an exercise for the reader
    */
    private function binDecode($binary, $min, $max)
    {
        $mid=($min+$max)/2;
        
        if (strlen($binary)==0)
            return $mid;
            
        $bit=substr($binary,0,1);
        $binary=substr($binary,1);
        
        if ($bit==1)
            return $this->binDecode($binary, $mid, $max);
        else
            return $this->binDecode($binary, $min, $mid);
    }
}

方案1:

这样,根据当前点坐标,我们可以得出搜索范围为

left-top    : (lat + dlat, lng - dlng)
right-top   : (lat + dlat, lng + dlng)
left-bottom : (lat - dlat, lng - dlng)
right-bottom: (lat - dlat, lng + dlng)

然后利用这个范围构造SQL语句,即可实现范围查询:

SELECT * FROM place WHERE lat > lat1 AND lat < lat2 AND lng > lng1 AND lng < lng2;



  根据中心点,和 上面的算法计算出几公里以内的最大/最小经纬度,然后搜索时用这个条件 (我们想要的为圆型的,需要过滤一次数据在),使用于数据量相对较小的

缺点:1.范围比较的索引利用率并不高,2.SQL语句极其不稳定(不同的当前位置会产生完全不同的SQL查询),很难缓存。

方案2:

  运用geohash, geohash是一种地址编码,它能把二维的经纬度编码成一维的字符串, 字符串匹配度越大,离的越近,适用于数据量较大的,

缺点:匹配程度并不能准确控制距离,只能找出比他大的范围,然后在用程序去判断

文章链接:

http://tech.idv2.com/2011/06/17/location-search/

http://tech.idv2.com/2011/07/05/geohash-intro/

http://www.wubiao.info/401


本文转载自:http://www.cnblogs.com/siqi/archive/2013/04/23/3037888.html

沉淀岁月
粉丝 27
博文 257
码字总数 91615
作品 0
朝阳
高级程序员
私信 提问
少年,买房的那些坑你知道吗?

文/充电实践 01 互联网流行的年代里,从来少不了房地产行业的话题,买房就像一个围城,进去的人发现被开发商坑了不少,没进去的刚需者挤着头皮也要进。对于年轻人,房子越来越成为一种生活的...

充电实践
2017/09/02
0
0
回望2017:一个前端从业者砥砺前行的一年

前言 从年前就嚷嚷着要走出去走出去,转眼间已经到了年底依然在我的大太原呆着。年底了,不能免俗的我,也来写一篇2017年度工作总结的文章,凑凑热闹。如果对你有一点点启发,或者感悟,那我...

闰土大叔
2018/01/02
0
0
寒门子弟自述:我的买房梦(一)

前言 最近一个月里,我不怎么在前端圈里活跃了,公众号也断更了两个多礼拜。有朋友问,闰土最近是不是又闭门造车去了,不是的,我是去看房了。91年的,现在都27岁了。即将或正在面临结婚的问...

2018/01/27
0
0
【056 生活 |谈谈买房经验】

“把买房当作一种投资行为,而不是消费,也不是需求。”相信持有这种观点的人不少,但是大多数都是一些已经在房产获利,或者专业炒房的人。 去年一整年,我几乎都在劝别人买房。随着国家去库...

ChallengerWu
2018/10/21
0
0
关于斐波纳挈数列的算法总结

斐波纳挈数列是一个很古老的数学算法了,这几天有必要把关于这个问题的算法总结一下:大概有3种算法吧,每种算法各有侧重点,出发点。还有其他的算法大家都交流一下吧:

段启超
2016/11/20
13
4

没有更多内容

加载失败,请刷新页面

加载更多

浅谈 Spark 的多语言支持

作者:郑锴,花名铁杰,阿里巴巴高级技术专家,Apache Hadoop PMC,Apache Kerby 创立者。深耕分布式系统开发和开源大数据多年,先后专注在安全,存储和计算领域。之前在 Intel,目前转战阿里...

阿里云云栖社区
30分钟前
2
0
Linux运维常见的硬件及系统问题

一、服务器常见故障和现象 1、有关服务器无法启动的主要原因 : ①市电或电源线故障(断电或接触不良) ②电源或电源模组故障 ③内存故障(一般伴有报警声) ④CPU故障(一般也会有报警声) ⑤主板故...

寰宇01
38分钟前
0
0
Confluence 6 针对 'unmigrated-wiki-markup' 宏重新尝试合并

在签名的章节中,我们主要是针对没有完全合并完成余下的为合并内容的异常处理。最常见的情况是内容以及被合并了,但是页面使用 wiki 标记的内容没有被合并,通常这些 wiki 标记的内容使用了 ...

honeymoose
48分钟前
2
0
ubuntu 18.04桌面版启动错误: Unable to mount root fs on unknown-block(0,0)

问题出现过程 *** 我的环境: visualbox 虚拟机 Ubuntu 18.04 桌面版 IP:192.168.1.186 (最初从 192.168.1.185 克隆过来的) 20190423 晚上准备安装一个 UNlet standalone 和 一个 Eclips...

wwzzhh166
49分钟前
1
0
fescar select for update 读隔离级别实现

/* * Copyright 1999-2018 Alibaba Group Holding Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in complian......

xiaomin0322
52分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部