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发电子邮件
Oct 09 PHP
PHP 伪静态隐藏传递参数名的四种方法
Feb 22 PHP
php中时间轴开发(刚刚、5分钟前、昨天10:23等)
Oct 03 PHP
PHP序列号生成函数和字符串替换函数代码
Jun 07 PHP
解析PHPExcel使用的常用说明以及把PHPExcel整合进CI框架的介绍
Jun 24 PHP
浅析php fwrite写入txt文件的时候用 \r\n不能换行的问题
Aug 06 PHP
php实现在线生成条形码示例分享(条形码生成器)
Dec 30 PHP
php一行代码获取文件后缀名实例分析
Nov 12 PHP
php搜索文件程序分享
Oct 30 PHP
php删除txt文件指定行及按行读取txt文档数据的方法
Jan 30 PHP
Yii 2.0自带的验证码使用经验分享
Jun 19 PHP
阿里对象存储OSS在laravel框架中的使用方法
Oct 13 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
解析csv数据导入mysql的方法
2013/07/01 PHP
Linux系统下php获得系统分区信息的方法
2015/03/30 PHP
php类的扩展和继承用法实例
2015/06/20 PHP
php中preg_match的isU代表什么意思
2015/10/01 PHP
前端必学之PHP语法基础
2016/01/01 PHP
jQuery的一些注意
2006/12/06 Javascript
JQuery 网站换肤功能实现代码
2009/11/02 Javascript
flash 得到自身url参数的代码
2009/11/15 Javascript
通过JavaScript控制字体大小的代码
2011/10/04 Javascript
ajax异步刷新实现更新数据库
2012/12/03 Javascript
jquery实现侧边弹出的垂直导航
2014/12/09 Javascript
JavaScript 实现的 zip 压缩和解压缩工具包Zip.js使用详解
2015/12/14 Javascript
一个简单不报错的summernote 图片上传案例
2016/07/11 Javascript
基于JavaScript实现屏幕滚动效果
2017/01/18 Javascript
前端跨域的几种解决方式总结(推荐)
2017/08/16 Javascript
浅谈vue,angular,react数据双向绑定原理分析
2017/11/28 Javascript
vue keep-alive 动态删除组件缓存的例子
2019/11/04 Javascript
vue中实现高德定位功能
2019/12/03 Javascript
JS 获取文件后缀,判断文件类型(比如是否为图片格式)
2020/05/09 Javascript
[03:05]DOTA2英雄基础教程 嗜血狂魔
2013/12/10 DOTA
Python中Random和Math模块学习笔记
2015/05/18 Python
详解python脚本自动生成需要文件实例代码
2017/02/04 Python
解决uWSGI的编码问题详解
2017/03/24 Python
Django + Uwsgi + Nginx 实现生产环境部署的方法
2018/06/20 Python
解决python pandas读取excel中多个不同sheet表格存在的问题
2020/07/14 Python
纯CSS3实现鼠标滑过按钮动画第二节
2020/07/16 HTML / CSS
HTML5中canvas中的beginPath()和closePath()的重要性
2018/08/24 HTML / CSS
是否可以从一个static方法内部发出对非static方法的调用?
2014/08/18 面试题
你的创业计划书怎样才能打动风投
2014/02/06 职场文书
写求职信有什么意义
2014/02/17 职场文书
工程造价专业大学生职业规划范文
2014/03/09 职场文书
初中优秀班集体申报材料
2014/05/01 职场文书
工厂仓管员岗位职责范本
2014/07/17 职场文书
普通党员群众路线教育实践活动心得体会
2014/11/04 职场文书
听证通知书
2015/04/24 职场文书
浅谈Golang 嵌套 interface 的赋值问题
2021/04/29 Golang