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 相关文章推荐
第十四节 命名空间 [14]
Oct 09 PHP
第一节--面向对象编程
Nov 16 PHP
php输出表格的实现代码(修正版)
Dec 29 PHP
浅析51个PHP处理字符串的函数
Aug 02 PHP
理解PHP中的stdClass类
Apr 18 PHP
dedecms集成财付通支付接口
Dec 28 PHP
php读取der格式证书乱码解决方法
Jun 22 PHP
php求今天、昨天、明天时间戳的简单实现方法
Jul 28 PHP
PHP二维数组去重实例分析
Nov 18 PHP
PHP 芝麻信用接入的注意事项
Dec 01 PHP
Yii2使用表单上传文件的实例代码
Aug 03 PHP
PHP命令Command模式用法实例分析
Aug 08 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查找字符串出现次数的方法
2014/12/01 PHP
如何在旧的PHP系统中使用PHP 5.3之后的库
2015/12/02 PHP
php微信公众号开发模式详解
2016/11/28 PHP
PHP实现简单用户登录界面
2019/10/23 PHP
激活 ActiveX 控件
2006/10/09 Javascript
符合标准的js表单提交的代码
2007/09/13 Javascript
js前台分页显示后端JAVA数据响应
2013/03/18 Javascript
jQuery学习笔记(1)--用jQuery实现异步通信(用json传值)具体思路
2013/04/08 Javascript
被遗忘的javascript的slice() 方法
2015/04/20 Javascript
HTML5 JS压缩图片并获取图片BASE64编码上传
2020/11/16 Javascript
Bootstrap3 datetimepicker控件使用实例
2016/12/13 Javascript
jQuery日程管理插件fullcalendar使用详解
2017/01/07 Javascript
js实现鼠标拖拽多选功能示例
2017/08/01 Javascript
详解Vue微信公众号开发踩坑全记录
2017/08/21 Javascript
使vue实现jQuery调用的两种方法
2019/05/12 jQuery
javascript实现简易聊天室
2019/07/12 Javascript
Vue 使用beforeEach实现登录状态检查功能
2019/10/31 Javascript
Python实现在线程里运行scrapy的方法
2015/04/07 Python
Python列表的切片实例讲解
2019/08/20 Python
pip 安装库比较慢的解决方法(国内镜像)
2019/10/06 Python
Python解压 rar、zip、tar文件的方法
2019/11/19 Python
Django models文件模型变更错误解决
2020/05/11 Python
快速解释如何使用pandas的inplace参数的使用
2020/07/23 Python
Python使用lambda抛出异常实现方法解析
2020/08/20 Python
Python 实现PS滤镜中的径向模糊特效
2020/12/03 Python
CHRONEXT英国:您的首选奢华腕表目的地
2020/03/30 全球购物
用C#语言写出在本地创建一个UDP接收端口的具体过程
2016/02/22 面试题
采购部岗位职责
2013/11/24 职场文书
小学生爱国演讲稿
2014/04/25 职场文书
社会稳定风险评估方案
2014/06/02 职场文书
思想作风纪律整顿心得体会
2014/09/04 职场文书
置业顾问岗位职责
2015/02/09 职场文书
大学生暑假实习总结
2015/07/13 职场文书
大学生安全教育主题班会
2015/08/12 职场文书
关于教师节的广播稿
2015/08/19 职场文书
golang中的并发和并行
2021/05/08 Golang