NokitaKaze

Вычисление расстояния между двумя точками на планете Земля

Mar 26th, 2016
153
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 3.90 KB | None | 0 0
  1. <?php
  2.  
  3.     /**
  4.      * Class Earth
  5.      * Земляшка
  6.      *
  7.      * @copyright https://tech.yandex.ru/maps/
  8.      */
  9.     abstract class Earth {
  10.         /**
  11.          * Длина одного градуса на конкретной широте
  12.          *
  13.          * @param float $gps_y Широта
  14.          *
  15.          * @return float
  16.          */
  17.         static function get_x_length($gps_y) {
  18.             return 0.00008516452991 * pow($gps_y, 3) - 0.02385660256 * pow($gps_y, 2) + 0.2589428868 * $gps_y + 107.75;
  19.         }
  20.  
  21.         /**
  22.          * Длина половины градуса на конкретной широте
  23.          *
  24.          * @param float $gps_x Широта
  25.          *
  26.          * @return float
  27.          */
  28.         static function get_y_length_05($gps_x) {
  29.             return -0.000002053898482 * pow($gps_x, 3) + 0.0002813579278 * pow($gps_x, 2) + 0.007 * $gps_x + 55.135;
  30.         }
  31.  
  32.         static function P($t) {
  33.             return max(min($t, 89.999), -89.999);
  34.         }
  35.  
  36.         static function h($t) {
  37.             return 0 > $t ? -1 : $t > 0 ? 1 : 0;
  38.         }
  39.  
  40.         const M = 6378137;
  41.         const i = 0.00335281066474682000653026208241;// 1 - sqrt(1 - 0.00669437999014);
  42.         const o = 6356752.3142451837116840090937925;// (1 - i) * M;
  43.         const c = 1e-10;
  44.  
  45.         static function r($t) {
  46.             return abs($t - self::h($t) * M_PI / 2) < self::c ? self::h($t) * M_PI / 2 : atan((1 - self::i) * tan($t));
  47.         }
  48.  
  49.         /**
  50.          * Вычисление расстояния между двумя точками на планете Земля
  51.          *
  52.          * @param float[] $t
  53.          * @param float[] $s
  54.          *
  55.          * @return float
  56.          */
  57.         static function get_distance($t, $s) {
  58.             if ($t == $s || $t[0] == $s[0] && $t[1] == $s[1]) {
  59.                 return 0;
  60.             }
  61.             $t[0] = self::P($t[0]);
  62.             $s[0] = self::P($s[0]);
  63.             if (($t[0] == 0) && ($s[0] == 0)) {
  64.                 $O = min(abs($s[1] - $t[1]), 180);
  65.  
  66.                 return 2 * M_PI * self::M / 360 * abs($O);
  67.             }
  68.  
  69.             $f = $t[0] * M_PI / 180;
  70.             $g = $s[0] * M_PI / 180;
  71.             $m = ($s[1] - $t[1]) * M_PI / 180;
  72.             $D = self::r($f);
  73.             $b = self::r($g);
  74.             $q = $m;
  75.             $p = $q;
  76.             $y = 0;
  77.             do {
  78.                 $R = sqrt(pow(cos($b) * sin($q), 2) + pow(cos($D) * sin($b) - sin($D) * cos($b) * cos($q), 2));
  79.                 $S = sin($D) * sin($b) + cos($D) * cos($b) * cos($q);
  80.                 $z = atan2($R, $S);
  81.                 $j = cos($D) * cos($b) * sin($q) / sin($z);
  82.                 $k = 1 - pow($j, 2);
  83.                 $A = cos($z) - 2 * sin($D) * sin($b) / $k;
  84.                 $B = self::i / 16 * $k * (4 + self::i * (4 - 3 * $k));
  85.                 $q = min(
  86.                     max($m + (1 - $B) * self::i * $j * ($z + $B * sin($z) * ($A + $B * cos($z) * (-1 + 2 * $A * $A))),
  87.                         -2 * M_PI), 2 * M_PI);
  88.                 $v = abs($p - $q);
  89.                 $p = $q;
  90.                 $y++;
  91.             } while ($v > self::c && 10 > $y);
  92.             $C = $k * (self::M * self::M - self::o * self::o) / (self::o * self::o);
  93.             $E = 1 + $C * (4096 + $C * (-768 + $C * (320 - 175 * $C))) / 16384;
  94.             $G = $C * (256 + $C * (-128 + $C * (74 - 47 * $C))) / 1024;
  95.             $H = $G * sin($z) *
  96.                  ($A + 0.25 * $G *
  97.                        (cos($z) * (-1 + 2 * $A * $A) -
  98.                         1 / 6 * $G * $A * (-3 + 4 * sin($z) * sin($z)) * (-3 + 4 * $A * $A)));
  99.  
  100.             return self::o * $E * ($z - $H);
  101.         }
  102.     }
  103.  
  104.     $collection = [];
  105.     for ($i = 0; $i < 20; $i++) {
  106.         $a = [mt_rand(20, 169), mt_rand(40, 77)];
  107.         $b = [mt_rand(20, 169), mt_rand(40, 77)];
  108.  
  109.         print_r(a, $b, Earth::get_distance($a, $b));
  110.     }
  111.  
  112. ?>
Add Comment
Please, Sign In to add comment