地球坐标转高德的火星坐标

<?php
/**
 * latlng转换器:从wgs84转换到gcj02
 *
 * 此处转换仅针对互联网民用地图,并假定:
 * 无测定时间(wg_week,wg_time永远为0),地图原点(0,0)(wg_flag永远为1)
 *
 * conf_random为true时,返回结果随机偏移。若要发布到外网服务,必须随机偏移!
 *
 * 验证方法可以从高德地图中验证。验证url:
 * http://mo.amap.com/?q=纬度,经度&name=park&dev=0#thirdpoi
 *
 * 也有在线转换方法,文档见:document/latlng_conv_online_wgs84_2_gcj02.txt
 *
 * @link http://blog.csdn.net/coolypf/article/details/8686588
 * @link https://on4wp7.codeplex.com/SourceControl/changeset/view/21483#353936
 * @author wgtochina_lb
 * @author coolypf
 * @author hl
 * @version 0.1
 *
 */
class LDB8{

    /**
     * @link http://bbs.esrichina-bj.cn/esri/viewthread.php?tid=65098
     * @var float
     */
    const DIMS_FULL_SCENE = 3686400.0;

    /**
     * Krasovsky 1940 (北京54)椭球长半轴
     * @var float
     */
    const ELLIPSOID_PARAM_A = 6378245.0;

    /**
     * Krasovsky 1940 (北京54)椭球长半轴第一偏心率平方
     * 计算方式:
     * 长半轴:
     * a = 6378245.0
     * 扁率:
     * 1/f = 298.3(变量相关计算为:(a-b)/a)
     * 短半轴:
     * b = 6356863.0188 (变量相关计算方法为:b = a * (1 - f))
     * 第一偏心率平方:
     * e2 = (a^2 - b^2) / a^2;
     */
    const ELLIPSOID_PARAM_E2 = 0.00669342162296594323;

    /**
     * 输出的中间量需要random混淆?
     * 如果要对外暴露使用,必须为true
     * @var bool
     */
    static protected $conf_random = true;

    /**
     * random值。self::$conf_random有效时使用
     * 初始值:0或者0.3
     * @var float
     */
    static protected $casm_rr = 0;

    /**
     * pi除以某个系数的结果
     * @var array
     */
    static protected $pi_div_result = array();

    /**
     * pi乘以某个系数的结果
     * @var array
     */
    static protected $pi_mul_result = array();

    /**
     * 转换接口
     * @param float|array $lat wgs84坐标系的纬度、或者array('lat'=>lat, 'lng'=>lng)
     * @param float $lng wgs84坐标系的经度
     * @param int $wg_heit wgs84坐标系的高度。缺省为0
     * @param int $random 输出的中间量需要random混淆?默认为0,表示跟随配置;-1表示强制禁用random混淆;其余数值表示强制启用random混淆
     * @return array 转换后的gcj02坐标(高德坐标系)。格式array('lat'=>lat, 'lng'=>lng)
     */
    static public function conv($lat, $lng = 0, $wg_heit = 0, $random = 0){
        if(is_array($lat)){
            $lng = isset($lat['lng']) ? $lat['lng'] : 0;
            $lat = isset($lat['lat']) ? $lat['lat'] : 0;
        }

        if(!self::is_conv_range($lat, $lng, $wg_heit)){
            return array(
                'lat' => $lat,
                'lng' => $lng,
            );
        }

        $x_l =  $lng;
        $y_l =  $lat;

        //此处直入
        $x_add = self::Transform_yj5($x_l - 105, $y_l - 35) ;
        $y_add = self::Transform_yjy5($x_l - 105, $y_l - 35) ;
        $h_add = $wg_heit;

        //由于猜测$wg_time = 0(个人猜测,应该是全部等于0,否则数据迁移很难搞...),后面的计算可省略
        $x_add = $x_add + $h_add * 0.001 /* + self::yj_sin2($wg_time*self::pi_div(180)) */;
        $y_add = $y_add + $h_add * 0.001 /* + self::yj_sin2($wg_time*self::pi_div(180)) */;

        if(0 == $random){
            if(false != self::$conf_random){
                $x_add += self::random_yj();
                $y_add += self::random_yj();
            }
        }elseif($random != -1){
            $x_add += self::random_yj();
            $y_add += self::random_yj();
        }

        return array(
            'lat' => ($y_l + self::Transform_jyj5($y_l, $y_add)),
            'lng' => ($x_l + self::Transform_jy5($y_l, $x_add)),
        );

    }

    /**
     * 是在需要转换的范畴么?
     * @param float $lat
     * @param float $lng
     * @return bool 不需要转换时,返回false
     */
    static public function is_conv_range($lat, $lng, $wg_heit = 0){
        if($lng < 72.004 ||  $lng > 137.8347){
            return false;
        }

        if($lat < 0.8293 || $lat > 55.8271){
            return false;
        }

        if($wg_heit > 5000){
            return false;
        }

        return true;

    }

    static public function Transform_yj5($x, $y){
        $tt = 300 + $x + 2 * $y + 0.1 * pow($x, 2) + 0.1 * $x * $y + 0.1 * sqrt(abs($x));

        $tt += (20 * self::yj_sin2(self::pi_mul(6) * $x) + 20 * self::yj_sin2(self::pi_mul(2) * $x))*2.0/3.0;
        $tt += (20 * self::yj_sin2(M_PI * $x) + 40 * self::yj_sin2(self::pi_div(3) * $x))*2.0/3.0;
        $tt += (150 * self::yj_sin2(self::pi_div(12) * $x) + 300 * self::yj_sin2(self::pi_div(30) * $x))*2.0/3.0;
        return $tt;
    }

    static public function Transform_yjy5($x , $y){
        $tt = -100 +  2 * $x + 3 * $y + 0.2 * pow($y, 2) + 0.1 * $x * $y + 0.2 * sqrt(abs($x));
        $tt = $tt + (20 * self::yj_sin2(self::pi_mul(6) * $x) + 20 * self::yj_sin2(self::pi_mul(2) * $x))*2.0/3.0;
        $tt = $tt + (20 * self::yj_sin2(M_PI * $y)+ 40 * self::yj_sin2(self::pi_div(3) * $y))*2.0/3.0;
        $tt = $tt + (160 * self::yj_sin2(self::pi_div(12) * $y) + 320 * self::yj_sin2(self::pi_div(30) * $y))*2.0/3.0;
        return $tt;
    }

    /**
     *
     * @param float $x
     * @return float
     */
    static public function yj_sin2($x){

        //另一种是直接返回sin($x)
        //return sin($x);

        $tt = $ss = $s2 = 0.0;
        $ff = 0;

        if($x < 0){
            $x *= -1;
            $ff = 1;
        }

        $tt = $x - intval($x / self::pi_mul(2)) * self::pi_mul(2);    //如果不考虑intval,$tt必定等于0

        if ($tt > M_PI){
            $tt -= M_PI;
            if ($ff==1){
                $ff=0;
            }elseif ($ff==0){
                $ff=1;
            }
        }

        //中间量若为0,则所有后续运算全部归0
        if(0 == $tt){
            return 0;
        }

        $x = $ss = $s2 = $tt;
        $tt=pow($tt, 2);

        //分别为3!,5!,7!,9!,11!
        foreach(array(6, 120, 5040, 362880, 39916800) as $index => $value){
            $s2 *= $tt;
            if(0 == $index % 2){
                $ss -= $s2 / $value;
            }else{
                $ss += $s2 / $value;
            }
        }

        if ($ff==1){
            $ss *= -1;
        }
        return $ss;

    }

    static public function random_yj(){
        $casm_rr = self::$casm_rr;

        $casm_rr = 314159269 * $casm_rr + 453806245;
        $casm_rr = $casm_rr - intval($casm_rr / 2) * 2;
        $casm_rr = $casm_rr / 2 ;

        self::$casm_rr = $casm_rr;
        return $casm_rr;
    }
    static public function Transform_jyj5($x, $yy){
        $mm = 1 - self::ELLIPSOID_PARAM_E2 * self::yj_sin2($x * self::pi_div(180)) * self::yj_sin2($x * self::pi_div(180)) ;
        $m = (self::ELLIPSOID_PARAM_A * (1 - self::ELLIPSOID_PARAM_E2)) / ($mm * sqrt($mm));
        return ($yy * 180) / ($m * M_PI);
    }

    static public function Transform_jy5($x , $xx){
        $n = sqrt (1 - self::ELLIPSOID_PARAM_E2 * self::yj_sin2($x * self::pi_div(180)) * self::yj_sin2($x * self::pi_div(180)));
        $n = ($xx * 180) /(self::ELLIPSOID_PARAM_A / $n * cos($x * self::pi_div(180)) * M_PI) ;
        return $n;
    }

    /**
     * pi除以
     * @param int $x
     */
    static public function pi_div($x = 1){
        if(!isset(self::$pi_div_result[$x])){
            self::$pi_div_result[$x] = (1 == $x) ? M_PI : (M_PI / $x);
        }
        return self::$pi_div_result[$x];
    }

    /**
     * pi乘以
     * @param int $x
     * @return float
     */
    static public function pi_mul($x = 1){
        if(!isset(self::$pi_mul_result[$x])){
            self::$pi_mul_result[$x] = (1 == $x) ? M_PI : (M_PI * $x);
        }
        return self::$pi_mul_result[$x];
    }

    /**
     * 获取或者设置conf_random的值
     * @param bool|null $val 为bool值时,表示要设置为对应值;其余情况下,返回当前设置值
     * @return bool
     */
    static public function conf_random($val = null){
        if(!is_bool($val)){
            return self::$conf_random;
        }
        self::$conf_random = $val;
        return $val;
    }

}

 

posted @ 2015-04-07 18:34  梦醒心晴  Views(1621)  Comments(0Edit  收藏  举报