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 相关文章推荐
如何分别全角和半角以避免乱码
Oct 09 PHP
谈谈PHP语法(3)
Oct 09 PHP
linux iconv方法的使用
Oct 01 PHP
php 生成唯一id的几种解决方法
Mar 08 PHP
PHP IDE PHPStorm配置支持友好Laravel代码提示方法
May 12 PHP
PHP中Closure类的使用方法及详解
Oct 09 PHP
PHP编程中尝试程序并发的几种方式总结
Mar 21 PHP
PHP创建word文档的方法(平台无关)
Mar 29 PHP
linux下php上传文件注意事项
Jun 11 PHP
CI(CodeIgniter)框架中URL特殊字符处理与SQL注入隐患分析
Feb 28 PHP
php命名空间设计思想、用法与缺点分析
Jul 17 PHP
通过PHP实现用户注册后邮箱验证激活
Nov 10 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将会员数据导入到ucenter的代码
2010/07/18 PHP
如何用PHP实现插入排序?
2013/04/10 PHP
php二维数组排序与默认自然排序的方法介绍
2013/04/27 PHP
php计算整个mysql数据库大小的方法
2015/06/19 PHP
Zend Framework+smarty用法实例详解
2016/03/19 PHP
Yii2中设置与获取别名的函数(setAlias和getAlias)用法分析
2016/07/25 PHP
ThinkPHP中create()方法自动验证表单信息
2017/04/28 PHP
在laravel中使用with实现动态添加where条件
2019/10/10 PHP
PHP常用字符串函数用法实例总结
2020/06/04 PHP
js FLASH幻灯片字符串中有连接符&的处理方法
2012/03/01 Javascript
深入理解Javascript里的依赖注入
2014/03/19 Javascript
java必学必会之static关键字
2015/12/03 Javascript
对象转换为原始值的实现方法
2016/06/06 Javascript
JavaScript prototype属性详解
2016/10/25 Javascript
javascript中Date对象的使用总结
2016/11/21 Javascript
JavaScript获取当前时间向前推三个月的方法示例
2017/02/04 Javascript
Angular4表单验证代码详解
2017/09/03 Javascript
使用react实现手机号的数据同步显示功能的示例代码
2018/04/03 Javascript
js实现简单音乐播放器
2020/06/30 Javascript
[47:20]DAC2018 4.4 淘汰赛 Optic vs Mineski 第一场
2018/04/05 DOTA
用Python编写分析Python程序性能的工具的教程
2015/04/01 Python
python3库numpy数组属性的查看方法
2018/04/17 Python
PyQt5每天必学之弹出消息框
2018/04/19 Python
英国泽西岛植物:Jersey Plants Direct
2019/08/07 全球购物
英国门销售网站:Green Tree Doors
2020/01/07 全球购物
linux面试题参考答案(10)
2013/11/04 面试题
数控专业个人求职信范例
2013/11/29 职场文书
公司合作意向书范文
2014/07/30 职场文书
2014年学校领导班子对照检查材料
2014/09/19 职场文书
汤姆叔叔的小屋读书笔记
2015/06/30 职场文书
大一新生军训新闻稿
2015/07/17 职场文书
网络研修随笔感言
2015/11/18 职场文书
2016年清明节寄语
2015/12/04 职场文书
忆童年!用Python实现愤怒的小鸟游戏
2021/06/07 Python
只用Python就可以制作的简单词云
2021/06/07 Python
如何设置多台电脑共享打印机?多台电脑共享打印机的方法
2022/04/08 数码科技