• 沙里软件

  • ShaliSoft.com [手机站]   办公桌收纳抽屉
  • 首页
  • 博文
  • 演示
  • 管理
  • gps纠偏数据库及gps纠偏算法PHP

    网络   2014/4/28 14:53:55
    利用0.01精度校正库offset.dat文件修正中国地图经纬度偏移。

    gps设备获取的经纬度跟实际地图经纬度有偏移,大陆地图是这样的。google地图存在偏移是众所周知的事实,说到底就是火星坐标系和真实gps之间的转换,我国所有的地图为了安全起见都作了加偏。

    具体偏移原因见: gps纠偏及大陆地图偏移原因。

    总之,gps是从卫星上获取的经纬度,是准确的:GPS坐标转换经纬度及换算方法。实际的地图都在原有的基础上加偏移值,天朝说是为了安全呗。因此,gps获取出来的经纬度直接在地图上展示,那肯定是不准确的,有偏差。当然不管google map,百度地图,搜狗地图等每一个都一样,但是他们的偏移算法肯定不一样,偏移的值也不一样。

    google的国内地图坐标都是加过密的,由高德提供。百度的地图数据也是加过密的,估计是四维提供。但是不同批次的数据加密后的坐标是有偏差的。总而言之,相对GPS数据,两种地图都是有偏差的。

    经纬度在http://maps.google.com和google earth上可以准确对应,但是在ditu.google.cn和百度地图上得到的总是偏移的

    既然有了偏移,就需要使用纠偏来解决gps定位问题,


    GPS坐标转百度坐标方法:

    http://api.map.baidu.com/ag/coord/convert?from=0&to=4&x=’.经度.’&y=’.纬度


    google目前没有类似百度这样的,只能通过纠偏数据库进行校验。

    纠偏数据库都是要钱的,0.001精度2-5k都有卖,我网上找到一个0.01精度的,是一个 offset.dat 文件, 总共74.9M,数据为9813675条,不敢独享,分享给大家.

    google纠偏数据库:

    http://file.yanue.net/map/offset.dat.

    基于该数据库,我搞个的纠偏接口

    免费纠偏接口: 

    http://map.yanue.net/gpsApi.php

    参数:

    lat: gps原始纬度,如22.502412986242,请保留小数点3位以上

    lng: gps原始经度,如113.93832783228,请保留小数点3位以上

    gps纠偏工具:

    http://map.yanue.net/gps.html

    说正题,有了偏移数据库之后,根据算法就可以完成目的了。

    下面贴出纠偏算法

    php利用offset.dat修正gps经纬度的算法:


    1. <?php

    2. /**

    3.  * gps经纬度修正

    4.  *

    5.  * 功能说明:利用0.01精度校正库offset.dat文件修正中国地图经纬度偏移。

    6.  *         该校正适用于 Google map China, Microsoft map china ,MapABC 等,这些地图构成方法是一样的。

    7.  * 使用方法:

    8.         $gps = new GpsOffset();

    9.         echo $gps->geoLatLng($lat,$lng);

    10.  * 注意: 请在服务器开启offset.dat读取权限

    11.  * @author yanue (yanue@outlook.com)

    12.  * @version 1.0

    13.  * @copyright yanue.net

    14.  * @time 2013-06-30

    15.  */


    16. class GpsOffset {

    17.     const datMax = 9813675;# 该文件最大数据为9813675条

    18.     private $fp = null;

    19.     /*

    20.      * 构造函数,打开 offset.dat 文件并初始化类中的信息

    21.      * @param string $filename

    22.      * @return null

    23.      */

    24.     function __construct($filename = "offset.dat") {

    25.         if (($this->fp = @fopen($filename, 'rb')) !== false) {

    26.             //注册析构函数,使其在程序执行结束时执行

    27.             register_shutdown_function(array(&$this, '__construct'));

    28.         }

    29.     }


    30.     /*

    31.      * 读取dat文件并查找偏移像素值

    32.      * 说明:

    33.      * dat文件结构:该文件为0.01精度校正数据,并以lng和lat递增形式组合.

    34.      * 其中以8个字节为一组:

    35.      * lng : 2字节经度,如12151表示121.51

    36.      * lat : 2字节纬度,如3130表示31.30

    37.      * x_off : 2字节地图x轴偏移像素值

    38.      * y_off : 2字节地图y轴偏移像素值

    39.      * 因此采用二分法并以lng+lat的值作为条件

    40.      * 注意:请在服务器开启offset.dat读取权限

    41.      *

    42.      */

    43.     private function fromEarthToMars($lat,$lng){

    44.         $tmpLng=intval($lng * 100);

    45.         $tmpLat=intval($lat * 100);

    46.         $left = 0; //开始记录

    47.         $right = self::datMax; //结束记录

    48.         $searchLngLat = $tmpLng.$tmpLat;

    49.         // 采用用二分法来查找查数据

    50.         while($left <= $right){

    51.             $recordCount =(floor(($left+$right)/2))*8; // 取半

    52.             fseek ( $this->fp, $recordCount , SEEK_SET ); // 设置游标

    53.             $c = fread($this->fp,8); // 读8字节

    54.             $lng = unpack('s',substr($c,0,2));

    55.             $lat = unpack('s',substr($c,2,2));

    56.             $x = unpack('s',substr($c,4,2));

    57.             $y = unpack('s',substr($c,6,2));

    58.             $curLngLat=$lng[1].$lat[1];

    59.             if ($curLngLat==$searchLngLat){

    60.                 fclose($this->fp);

    61.                 return array('x'=>$x[1],'y'=>$y[1]);

    62.                 break;

    63.             }else if($curLngLat<$searchLngLat){

    64.                 $left=($recordCount/8) + 1;

    65.             }else if($curLngLat>$searchLngLat){

    66.                 $right=($recordCount/8) - 1;

    67.             }

    68.         }

    69.         fclose($this->fp);

    70.         return false;

    71.     }


    72.     // 转换经纬度到

    73.     public function geoLatLng($lat,$lng){

    74.         $offset =$this->fromEarthToMars($lat,$lng);

    75.         $lngPixel=$this->lngToPixel($lng,18)+$offset['x'];

    76.         $latPixel=$this->latToPixel($lat,18)+$offset['y'];

    77.         $mixLat = $this->pixelToLat($latPixel,18);

    78.         $mixLng = $this->pixelToLng($lngPixel,18);

    79.         return array('lat'=>$mixLat,'lng'=>$mixLng);

    80.     }

    81.     //经度到像素X值

    82.     private function lngToPixel($lng,$zoom) {

    83.         return ($lng+180)*(256<<$zoom)/360;

    84.     }


    85.     //纬度到像素Y值

    86.     private function latToPixel($lat, $zoom) {

    87.         $siny = sin($lat * pi() / 180);

    88.         $y=log((1+$siny)/(1-$siny));

    89.         return (128<<$zoom)*(1-$y/(2*pi()));

    90.     }


    91.     //像素X到经度

    92.     private function pixelToLng($pixelX,$zoom){

    93.         return $pixelX*360/(256<<$zoom)-180;

    94.     }


    95.     //像素Y到纬度

    96.     private function pixelToLat($pixelY, $zoom) {

    97.         $y = 2*pi()*(1-$pixelY /(128 << $zoom));

    98.         $z = pow(M_E, $y);

    99.         $siny = ($z -1)/($z +1);

    100.         return asin($siny) * 180/pi();

    101.     }


    102.     public function __destruct(){

    103.         if($this->fp){

    104.             fclose($this->fp);

    105.         }

    106.         $this->fp = null;

    107.     }

    108. }

    C#

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;   
     
    namespace MapDigit.GIS
    {
        public class GeoLatLng
        {   
     
            public GeoLatLng(double latitude, double longitude)
            {
                this.latitude = latitude;
                this.longitude = longitude;
            }
            public double latitude;
            public double longitude;
        }   
     
        public class GeoPoint
        {
            public GeoPoint(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
            public int x;
            public int y;
        }   
     
        public class OffsetInChina
        {
            //用于从GPS坐标转换为偏移后坐标
            public static GeoLatLng fromEarthToMars(GeoLatLng earth)
            {
                GeoPoint ptOffset = getOffset(earth.latitude, earth.longitude);
                if (ptOffset.x != 0 || ptOffset.y != 0)
                {
                    int pixelX, pixelY;
                    TileSystem.LatLongToPixelXY(earth.latitude, earth.longitude, 18, out pixelX, out pixelY);
                    GeoPoint pt = new GeoPoint(pixelX, pixelY);
                    pt.x += ptOffset.x;
                    pt.y += ptOffset.y;
                    double latitude, longitude;
                    TileSystem.PixelXYToLatLong(pt.x, pt.y, 18, out latitude, out longitude);
                    return new GeoLatLng(latitude, longitude);   
     
                }
                else
                {
                    return new GeoLatLng(earth.latitude, earth.longitude);
                }   
     
            }   
     
            //用于将偏移后坐标转成真实的坐标
            public static GeoLatLng fromMarToEarth(GeoLatLng mars)
            {
                GeoPoint ptOffset = getOffset(mars.latitude, mars.longitude);
                if (ptOffset.x != 0 || ptOffset.y != 0)
                {
                    int pixelX, pixelY;
                    TileSystem.LatLongToPixelXY(mars.latitude, mars.longitude, 18, out pixelX, out pixelY);
                    GeoPoint pt = new GeoPoint(pixelX, pixelY);
                    pt.x -= ptOffset.x;
                    pt.y -= ptOffset.y;
                    double latitude, longitude;
                    TileSystem.PixelXYToLatLong(pt.x, pt.y, 18, out latitude, out longitude);
                    return new GeoLatLng(latitude, longitude);   
     
                }
                else
                {
                    return new GeoLatLng(mars.latitude, mars.longitude);
                }
            }   
     
            //这个函数用于将需要查询的经纬度转成最近的0.01分度值,无插值
            //也可以自行实现插值
            private static GeoPoint getQueryLocation(double latitude, double longitude)
            {
                int lat = (int)(latitude * 100);
                int lng = (int)(longitude * 100);
                double lat1 = ((int)(latitude * 1000 + 0.499999)) / 10.0;
                double lng1 = ((int)(longitude * 1000 + 0.499999)) / 10.0;
                for (double x = longitude; x < longitude + 1; x += 0.5)
                {
                    for (double y = latitude; x < latitude + 1; y += 0.5)
                    {
                        if (x <= lng1 && lng1 < (x + 0.5) && lat1 >= y && lat1 < (y + 0.5))
                        {
                            return new GeoPoint((int)(x + 0.5), (int)(y + 0.5));
                        }
                    }
                }
                return new GeoPoint(lng, lat);
            }   
     
            private static GeoPoint getOffset(double longitude, double latitude)
            {
                //这个函数用于返回查询结果,就是从校正数据中返回18级时x,y方偏移
                //可以自行实现
                return null;
            }   
     
        }
    }


    参考文章:http://go2log.com/2011/08/30/%E4%B8%AD%E5%9B%BD%E5%9C%B0%E5%9B%BE%E5%81%8F%E7%A7%BB%E6%A0%A1%E6%AD%A3php%E7%AE%97%E6%B3%95/(有c#算法)至此,文章完


    阅读(1779) 分享(0)

    上一篇: gps纠偏及大陆地图偏移原因
    下一篇: BMap百度地图坐标转换为GPS坐标

  • 精彩推荐

    ◆ Windows Server 2003操作系统单网卡搭建VPN服务器
    ◆ PHP中9大缓存技术总结
    ◆ 微信订阅号授权登录,订阅号怎么实现网页授权登录?
    ◆ jQuery对应的原生js写法
    ◆ 国外程序员整理的PHP资源大全
    ◆ ASP语言使用淘宝接口遇中文字符签名失败解决方法
    ◆ 大型网站图片服务器架构的演
    ◆ php+Mysql 高速分页优化,百万至千万级快速分页
    ◆ 从MyISAM转到InnoDB需要注意什么
    ◆ 新型DDoS攻击LFA 网易网络被攻击原因
  • 用心做事 不能唯利是图

    • 吊儿
    • 用QQ联系我17905772
  • 搜索


  • 最新文章

    • 导出Excel 格式 mso-number-format
    • 服务器iis支持tls1.2,windows server 2008 r2 中IIS启用TLS 1.2(安装SSL后用TLS 1.2)
    • MySQL配置优化
    • EditPlus 添加文件比较工具winmerge
    • 滚动悬浮固定JS特效

  • 热门文章

    • php sso单点登录实现代码
    • 中国菜刀(China chopper) 最新黑客工具
    • redis.conf中文版(基于2.4)
    • 搜索引擎名单大全
    • php图片上传类,支持加水印,生成略缩图

  • 最新图库


  • 最新评论


  • 友情链接

  • 沙里软件

  • 最近访客

    Powered by ShaliSoft.com 豫ICP备13008529号

    免责声明:本站部分内容来源于互联网,转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,不为其版权负责,也不构成任何其他建议。如果发现侵犯版权,联系QQ17905772进行删除。