PHP实现搜索地理位置及计算两点地理位置间距离的实例


Posted in PHP onJanuary 08, 2016

地理位置搜寻
LBS,存储每个地点的经纬度坐标,搜寻附近的地点,建立地理位置索引可提高查询效率。
mongodb地理位置索引,2d和2dsphere,对应平面和球面。

1.创建lbs集合存放地点坐标

use lbs; 
 
db.lbs.insert( 
  { 
    loc:{ 
      type: "Point", 
      coordinates: [113.332264, 23.156206] 
    }, 
    name: "广州东站" 
  } 
) 
 
db.lbs.insert( 
  { 
    loc:{ 
      type: "Point", 
      coordinates: [113.330611, 23.147234] 
    }, 
    name: "林和西" 
  } 
) 
 
db.lbs.insert( 
  { 
    loc:{ 
      type: "Point", 
      coordinates: [113.328095, 23.165376] 
    }, 
    name: "天平架" 
  } 
)

2.创建地理位置索引

db.lbs.ensureIndex( 
  { 
    loc: "2dsphere" 
  } 
)

3.查询附近的坐标
当前位置为:时代广场,
坐标:

113.323568, 23.146436

搜寻附近一公里内的点,由近到远排序

db.lbs.find( 
  { 
    loc: { 
      $near:{ 
        $geometry:{ 
          type: "Point", 
          coordinates: [113.323568, 23.146436] 
        }, 
        $maxDistance: 1000 
      } 
    } 
  } 
)

搜寻结果:

{ "_id" : ObjectId("556a651996f1ac2add8928fa"), "loc" : { "type" : "Point", "coordinates" : [ 113.330611, 23.147234 ] }, "name" : "林和西" } 

php代码如下:

<?php 
// 连接mongodb 
function conn($dbhost, $dbname, $dbuser, $dbpasswd){ 
  $server = 'mongodb://'.$dbuser.':'.$dbpasswd.'@'.$dbhost.'/'.$dbname; 
  try{ 
    $conn = new MongoClient($server); 
    $db = $conn->selectDB($dbname); 
  } catch (MongoException $e){ 
    throw new ErrorException('Unable to connect to db server. Error:' . $e->getMessage(), 31); 
  } 
  return $db; 
} 
 
// 插入坐标到mongodb 
function add($dbconn, $tablename, $longitude, $latitude, $name){ 
  $index = array('loc'=>'2dsphere'); 
  $data = array( 
      'loc' => array( 
          'type' => 'Point', 
          'coordinates' => array(doubleval($longitude), doubleval($latitude)) 
      ), 
      'name' => $name 
  ); 
  $coll = $dbconn->selectCollection($tablename); 
  $coll->ensureIndex($index); 
  $result = $coll->insert($data, array('w' => true)); 
  return (isset($result['ok']) && !empty($result['ok'])) ? true : false; 
} 
 
// 搜寻附近的坐标 
function query($dbconn, $tablename, $longitude, $latitude, $maxdistance, $limit=10){ 
  $param = array( 
    'loc' => array( 
      '$nearSphere' => array( 
        '$geometry' => array( 
          'type' => 'Point', 
          'coordinates' => array(doubleval($longitude), doubleval($latitude)),  
        ), 
        '$maxDistance' => $maxdistance*1000 
      ) 
    ) 
  ); 
 
  $coll = $dbconn->selectCollection($tablename); 
  $cursor = $coll->find($param); 
  $cursor = $cursor->limit($limit); 
   
  $result = array(); 
  foreach($cursor as $v){ 
    $result[] = $v; 
  }  
 
  return $result; 
} 
 
$db = conn('localhost','lbs','root','123456'); 
 
// 随机插入100条坐标纪录 
for($i=0; $i<100; $i++){ 
  $longitude = '113.3'.mt_rand(10000, 99999); 
  $latitude = '23.15'.mt_rand(1000, 9999); 
  $name = 'name'.mt_rand(10000,99999); 
  add($db, 'lbs', $longitude, $latitude, $name); 
} 
 
// 搜寻一公里内的点 
$longitude = 113.323568; 
$latitude = 23.146436; 
$maxdistance = 1; 
$result = query($db, 'lbs', $longitude, $latitude, $maxdistance); 
print_r($result); 
?>

演示php代码,首先需要在mongodb的lbs中创建用户和执行auth。方法如下:

use lbs; 
db.createUser( 
  { 
    "user":"root", 
    "pwd":"123456", 
    "roles":[] 
  } 
) 
 
db.auth( 
  { 
    "user":"root", 
    "pwd":"123456" 
  } 
)

计算两点地理坐标的距离
功能:根据圆周率和地球半径系数与两点坐标的经纬度,计算两点之间的球面距离。

获取两点坐标距离:

<?php
/**
 * 计算两点地理坐标之间的距离
 * @param Decimal $longitude1 起点经度
 * @param Decimal $latitude1 起点纬度
 * @param Decimal $longitude2 终点经度 
 * @param Decimal $latitude2 终点纬度
 * @param Int   $unit    单位 1:米 2:公里
 * @param Int   $decimal  精度 保留小数位数
 * @return Decimal
 */
function getDistance($longitude1, $latitude1, $longitude2, $latitude2, $unit=2, $decimal=2){

  $EARTH_RADIUS = 6370.996; // 地球半径系数
  $PI = 3.1415926;

  $radLat1 = $latitude1 * $PI / 180.0;
  $radLat2 = $latitude2 * $PI / 180.0;

  $radLng1 = $longitude1 * $PI / 180.0;
  $radLng2 = $longitude2 * $PI /180.0;

  $a = $radLat1 - $radLat2;
  $b = $radLng1 - $radLng2;

  $distance = 2 * asin(sqrt(pow(sin($a/2),2) + cos($radLat1) * cos($radLat2) * pow(sin($b/2),2)));
  $distance = $distance * $EARTH_RADIUS * 1000;

  if($unit==2){
    $distance = $distance / 1000;
  }

  return round($distance, $decimal);

}

// 起点坐标
$longitude1 = 113.330405;
$latitude1 = 23.147255;

// 终点坐标
$longitude2 = 113.314271;
$latitude2 = 23.1323;

$distance = getDistance($longitude1, $latitude1, $longitude2, $latitude2, 1);
echo $distance.'m'; // 2342.38m

$distance = getDistance($longitude1, $latitude1, $longitude2, $latitude2, 2);
echo $distance.'km'; // 2.34km

?>
PHP 相关文章推荐
PHP 和 MySQL 基础教程(四)
Oct 09 PHP
php中去除所有js,html,css代码
Oct 12 PHP
php分页思路以及在ZF中的使用
May 30 PHP
浏览器预览PHP文件时顶部出现空白影响布局分析原因及解决办法
Jan 11 PHP
PHP 5.5 创建和验证哈希最简单的方法详解
Nov 07 PHP
ThinkPHP3.1新特性之动态设置自动完成及自动验证示例代码
Jun 23 PHP
Symfony2使用第三方库Upload制作图片上传实例详解
Feb 04 PHP
thinkPHP多域名情况下使用memcache方式共享session数据的实现方法
Jul 21 PHP
php魔术方法功能与用法实例分析
Oct 19 PHP
PHP的mysqli_stmt_init()函数讲解
Jan 24 PHP
PHP simplexml_load_string()函数实例讲解
Feb 03 PHP
php上传后台无法收到数据解决方法
Oct 28 PHP
PHP使用数组依次替换字符串中匹配项
Jan 08 #PHP
PHP 7.0.2 正式版发布
Jan 08 #PHP
深入浅析php中sprintf与printf函数的用法及区别
Jan 08 #PHP
PHP中each与list用法分析
Jan 08 #PHP
PHP中list()函数用法实例简析
Jan 08 #PHP
PHP图像裁剪缩略裁切类源码及使用方法
Jan 07 #PHP
PHP中substr_count()函数获取子字符串出现次数的方法
Jan 07 #PHP
You might like
用PHP 快速生成 Flash 动画的方法
2007/03/06 PHP
基于linnux+phantomjs实现生成图片格式的网页快照
2015/04/15 PHP
PDO::getAvailableDrivers讲解
2019/01/28 PHP
PHP标准库(PHP SPL)详解
2019/03/16 PHP
javascript radio 联动效果
2009/03/04 Javascript
javascript 关于# 和 void的区别分析
2009/10/26 Javascript
JavaScript的类型转换(字符转数字 数字转字符)
2010/08/30 Javascript
js实现点小图看大图效果的思路及示例代码
2013/10/28 Javascript
jQuery/CSS3图片特效插件整理推荐
2014/12/07 Javascript
jQuery不使用插件及swf实现无刷新文件上传
2014/12/08 Javascript
jquery.form.js框架实现文件上传功能案例解析(springmvc)
2016/05/26 Javascript
Parcel 打包示例(React HelloWorld)
2018/01/16 Javascript
react中实现搜索结果中关键词高亮显示
2018/07/31 Javascript
jQuery实现的简单手风琴效果示例
2018/08/29 jQuery
浅谈JavaScript 代码简洁之道
2019/01/09 Javascript
Vue使用Proxy监听所有接口状态的方法实现
2019/06/07 Javascript
node 标准输入流和输出流代码实例
2019/09/19 Javascript
微信小程序实现上传多张图片、删除图片
2020/07/29 Javascript
python通过定义一个类实例作为ftp回调方法
2015/05/04 Python
Python使用MONGODB入门实例
2015/05/11 Python
详解Python3中的Sequence type的使用
2015/08/01 Python
利用Python实现图书超期提醒
2016/08/02 Python
PyQt5实现拖放功能
2018/04/25 Python
python 获取当天凌晨零点的时间戳方法
2018/05/22 Python
解决pyinstaller打包exe文件出现命令窗口一闪而过的问题
2018/10/31 Python
python实现浪漫的烟花秀
2019/01/30 Python
python实现点击按钮修改数据的方法
2019/07/17 Python
Python中logging日志记录到文件及自动分割的操作代码
2020/08/05 Python
python如何实现DES加密
2020/09/21 Python
python在协程中增加任务实例操作
2021/02/28 Python
HTML5 FileReader对象的具体使用方法
2020/05/22 HTML / CSS
印尼最大的网上书店:Gramedia.com
2018/09/13 全球购物
个人查摆问题整改措施
2014/10/04 职场文书
2014年教育实习工作总结
2014/11/22 职场文书
施工安全保证书
2015/05/09 职场文书
gateway与spring-boot-starter-web冲突问题的解决
2021/07/16 Java/Android