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

 

    /**

     * 根据经纬度计算距离 其中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;

}
 
   

 

 
关于计算周围多少里以内的楼盘 View Code
  1 /**

  2  * Geohash generation class

  3  * http://blog.dixo.net/downloads/

  4  *

  5  * This file copyright (C) 2008 Paul Dixon ([email protected])

  6  *

  7  * This program is free software; you can redistribute it and/or

  8  * modify it under the terms of the GNU General Public License

  9  * as published by the Free Software Foundation; either version 3

 10  * of the License, or (at your option) any later version.

 11  *

 12  * This program is distributed in the hope that it will be useful,

 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of

 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

 15  * GNU General Public License for more details.

 16  *

 17  * You should have received a copy of the GNU General Public License

 18  * along with this program; if not, write to the Free Software

 19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

 20  */

 21 

 22 

 23 

 24 /**

 25 * Encode and decode geohashes

 26 *

 27 */

 28 class Geohash

 29 {

 30     private $coding="0123456789bcdefghjkmnpqrstuvwxyz";

 31     private $codingMap=array();

 32     

 33     public function Geohash()

 34     {

 35         //build map from encoding char to 0 padded bitfield

 36         for($i=0; $i<32; $i++)

 37         {

 38             $this->codingMap[substr($this->coding,$i,1)]=str_pad(decbin($i), 5, "0", STR_PAD_LEFT);

 39         }

 40         

 41     }

 42     

 43     /**

 44     * Decode a geohash and return an array with decimal lat,long in it

 45     */

 46     public function decode($hash)

 47     {

 48         //decode hash into binary string

 49         $binary="";

 50         $hl=strlen($hash);

 51         for($i=0; $i<$hl; $i++)

 52         {

 53             $binary.=$this->codingMap[substr($hash,$i,1)];

 54         }

 55         

 56         //split the binary into lat and log binary strings

 57         $bl=strlen($binary);

 58         $blat="";

 59         $blong="";

 60         for ($i=0; $i<$bl; $i++)

 61         {

 62             if ($i%2)

 63                 $blat=$blat.substr($binary,$i,1);

 64             else

 65                 $blong=$blong.substr($binary,$i,1);

 66             

 67         }

 68         

 69         //now concert to decimal

 70         $lat=$this->binDecode($blat,-90,90);

 71         $long=$this->binDecode($blong,-180,180);

 72         

 73         //figure out how precise the bit count makes this calculation

 74         $latErr=$this->calcError(strlen($blat),-90,90);

 75         $longErr=$this->calcError(strlen($blong),-180,180);

 76                 

 77         //how many decimal places should we use? There's a little art to

 78         //this to ensure I get the same roundings as geohash.org

 79         $latPlaces=max(1, -round(log10($latErr))) - 1;

 80         $longPlaces=max(1, -round(log10($longErr))) - 1;

 81         

 82         //round it

 83         $lat=round($lat, $latPlaces);

 84         $long=round($long, $longPlaces);

 85         

 86         return array($lat,$long);

 87     }

 88 

 89     

 90     /**

 91     * Encode a hash from given lat and long

 92     */

 93     public function encode($lat,$long)

 94     {

 95         //how many bits does latitude need?    

 96         $plat=$this->precision($lat);

 97         $latbits=1;

 98         $err=45;

 99         while($err>$plat)

100         {

101             $latbits++;

102             $err/=2;

103         }

104         

105         //how many bits does longitude need?

106         $plong=$this->precision($long);

107         $longbits=1;

108         $err=90;

109         while($err>$plong)

110         {

111             $longbits++;

112             $err/=2;

113         }

114         

115         //bit counts need to be equal

116         $bits=max($latbits,$longbits);

117         

118         //as the hash create bits in groups of 5, lets not

119         //waste any bits - lets bulk it up to a multiple of 5

120         //and favour the longitude for any odd bits

121         $longbits=$bits;

122         $latbits=$bits;

123         $addlong=1;

124         while (($longbits+$latbits)%5 != 0)

125         {

126             $longbits+=$addlong;

127             $latbits+=!$addlong;

128             $addlong=!$addlong;

129         }

130         

131         

132         //encode each as binary string

133         $blat=$this->binEncode($lat,-90,90, $latbits);

134         $blong=$this->binEncode($long,-180,180,$longbits);

135         

136         //merge lat and long together

137         $binary="";

138         $uselong=1;

139         while (strlen($blat)+strlen($blong))

140         {

141             if ($uselong)

142             {

143                 $binary=$binary.substr($blong,0,1);

144                 $blong=substr($blong,1);

145             }

146             else

147             {

148                 $binary=$binary.substr($blat,0,1);

149                 $blat=substr($blat,1);

150             }

151             $uselong=!$uselong;

152         }

153         

154         //convert binary string to hash

155         $hash="";

156         for ($i=0; $i<strlen($binary); $i+=5)

157         {

158             $n=bindec(substr($binary,$i,5));

159             $hash=$hash.$this->coding[$n];

160         }

161         

162         

163         return $hash;

164     }

165     

166     /**

167     * What's the maximum error for $bits bits covering a range $min to $max

168     */

169     private function calcError($bits,$min,$max)

170     {

171         $err=($max-$min)/2;

172         while ($bits--)

173             $err/=2;

174         return $err;

175     }

176     

177     /*

178     * returns precision of number

179     * precision of 42 is 0.5

180     * precision of 42.4 is 0.05

181     * precision of 42.41 is 0.005 etc

182     */

183     private function precision($number)

184     {

185         $precision=0;

186         $pt=strpos($number,'.');

187         if ($pt!==false)

188         {

189             $precision=-(strlen($number)-$pt-1);

190         }

191         

192         return pow(10,$precision)/2;

193     }

194     

195     

196     /**

197     * create binary encoding of number as detailed in http://en.wikipedia.org/wiki/Geohash#Example

198     * removing the tail recursion is left an exercise for the reader

199     */

200     private function binEncode($number, $min, $max, $bitcount)

201     {

202         if ($bitcount==0)

203             return "";

204         

205         #echo "$bitcount: $min $max<br>";

206             

207         //this is our mid point - we will produce a bit to say

208         //whether $number is above or below this mid point

209         $mid=($min+$max)/2;

210         if ($number>$mid)

211             return "1".$this->binEncode($number, $mid, $max,$bitcount-1);

212         else

213             return "0".$this->binEncode($number, $min, $mid,$bitcount-1);

214     }

215     

216 

217     /**

218     * decodes binary encoding of number as detailed in http://en.wikipedia.org/wiki/Geohash#Example

219     * removing the tail recursion is left an exercise for the reader

220     */

221     private function binDecode($binary, $min, $max)

222     {

223         $mid=($min+$max)/2;

224         

225         if (strlen($binary)==0)

226             return $mid;

227             

228         $bit=substr($binary,0,1);

229         $binary=substr($binary,1);

230         

231         if ($bit==1)

232             return $this->binDecode($binary, $mid, $max);

233         else

234             return $this->binDecode($binary, $min, $mid);

235     }

236 }

 

方案1:

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

缺点: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

 

  

 

你可能感兴趣的:(计算)