EpsgConversion.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. <?php
  2. class Complex {
  3. private $real = 0;
  4. private $imag = 0;
  5. public function __debugInfo() {
  6. return null;
  7. }
  8. public function __invoke() {
  9. return null;
  10. }
  11. public function __construct($real = 0, $imag = 0) {
  12. if ($real instanceof Complex) {
  13. $this->real = $real->real;
  14. $this->imag = $real->imag;
  15. } elseif (is_scalar($real) && is_scalar($imag)) {
  16. $this->real = (float)$real;
  17. $this->imag = (float)$imag;
  18. } else throw new Exception("Bad argument(s)");
  19. }
  20. public function abs() {
  21. return sqrt($this->real * $this->real - $this->imag * $this->imag);
  22. }
  23. public function add($c) {
  24. $c = new Complex($c);
  25. return new Complex(
  26. $this->real + $c->real,
  27. $this->imag + $c->imag
  28. );
  29. }
  30. public function multiply($c) {
  31. $c = new Complex($c);
  32. return new Complex(
  33. $this->real * $c->real - $this->imag * $c->imag,
  34. $this->real * $c->imag + $this->imag * $c->real
  35. );
  36. }
  37. public function real() {
  38. return $this->real;
  39. }
  40. public function imag() {
  41. return $this->imag;
  42. }
  43. }
  44. class EpsgConversion {
  45. private static $fe = 500000;
  46. private static function CalculateESquared($a, $b) {
  47. return (pow($a, 2) - pow($b, 2)) / pow($a, 2);
  48. }
  49. private static function CalculateE2Squared($a, $b) {
  50. return (pow($a, 2) - pow($b, 2)) / pow($b, 2);
  51. }
  52. private static function denom ($es, $sphi) {
  53. $sinSphi = sin($sphi);
  54. return sqrt(1 - $es * pow($sinSphi, 2));
  55. }
  56. private static function sphsr ($a, $es, $sphi) {
  57. $dn = self::denom($es, $sphi);
  58. return $a * (1 - $es) / pow($dn, 3);
  59. }
  60. private static function sphsn ($a, $es, $sphi) {
  61. $sinSphi = sin($sphi);
  62. return $a / sqrt(1 - $es * pow($sinSphi, 2));
  63. }
  64. private static function sphtmd ($ap, $bp, $cp, $dp, $ep, $sphi) {
  65. return ($ap * $sphi) - ($bp * sin(2 * $sphi)) + ($cp * sin(4 * $sphi)) - ($dp * sin(6 * $sphi)) + ($ep * sin(8 * $sphi));
  66. }
  67. private static function LonLatToPuwg($a, $f, $x, $y, $proj) {
  68. if ($x < 13.5 || $x >= 25.5) throw new Exception("Wrong longitude - {$x}");
  69. if ($proj == 1) {
  70. $alam = 19 * M_PI / 180;
  71. $strf = 0;
  72. $nfn = -5300000.0;
  73. $ok = 0.9993;
  74. } else {
  75. $nfn = 0;
  76. $olam = floor(($x + 1.5)/3) * M_PI / 60;
  77. $strf = floor(($x + 1.5)/3) * 1000000;
  78. $ok = 0.999923;
  79. }
  80. $result = new StdClass();
  81. $latRad = $y * M_PI / 180;
  82. $lonRad = $x * M_PI / 180;
  83. $recf = 1 / $f;
  84. $b = $a * ($recf - 1) / $recf;
  85. $eSquared = self::CalculateESquared($a, $b);
  86. $e2Squared = self::CalculateE2Squared ($a, $b);
  87. $tn = ($a - $b) / ($a + $b);
  88. $ap = $a * (1 - $tn + 5 * (pow($tn, 2) - pow($tn, 3)) / 4 + 81 * (pow($tn, 4) - pow($tn, 5)) / 64);
  89. $bp = 3 * $a * ($tn - pow($tn, 2) + 7 * (pow($tn, 3) - pow($tn, 4)) / 8 + 55 * pow($tn, 5) / 64) / 2;
  90. $cp = 15 * $a * (pow($tn, 2) - pow($tn, 3) + 3 * (pow($tn, 4) - pow($tn, 5)) / 4) / 16;
  91. $dp = 35 * $a * (pow($tn, 3) - pow($tn, 4) + 11 * pow($tn, 5) / 16) / 48;
  92. $ep = 315 * $a * (pow($tn, 4) - pow($tn, 5)) / 512;
  93. $dlam = $lonRad - $olam;
  94. $s = sin($latRad);
  95. $c = cos($latRad);
  96. $t = $s / $c;
  97. $eta = $e2Squared * pow($c, 2);
  98. $sn = self::sphsn($a, $eSquared, $latRad);
  99. $tmd = self::sphtmd($ap, $bp, $cp, $dp, $ep, $latRad);
  100. $t1 = $tmd * $ok;
  101. $t2 = $sn * $s * $c * $ok / 2;
  102. $t3 = $sn * $s * pow($c, 3) * $ok * (5 - pow($t, 2) + 9 * $eta + 4 * pow($eta, 2)) / 24;
  103. $t4 = $sn * $s * pow($c, 5) * $ok * (61 - 58 * pow($t, 2) + pow($t, 4) + 270 * $eta - 330 * pow($t, 2) * $eta + 445 * pow($eta, 2) + 324 * pow($eta, 3) - 680 * pow($t, 2) * pow($eta, 2) + 88 * pow($eta, 4) - 600 * pow($t, 2) * pow($eta, 3) - 192 * pow($t, 2) * pow($eta, 4)) / 720;
  104. $t5 = $sn * $s * pow($c, 7) * $ok * (1385 - 3111 * pow($t, 2) + 543 * pow($t, 4) - pow($t, 6)) / 40320;
  105. $t6 = $sn * $c * $ok;
  106. $t7 = $sn * pow($c, 3) * $ok * (1 - pow($t, 2) + $eta) / 6;
  107. $t8 = $sn * pow($c, 5) * $ok * (5 - 18 * pow($t, 2) + pow($t, 4) + 14 * $eta - 58 * pow($t, 2) * $eta + 13 * pow($eta, 2) + 4 * pow($eta, 3) - 64 * pow($t, 2) * pow($eta, 2) - 24 * pow($t, 2) * pow($eta, 3)) / 120;
  108. $t9 = $sn * pow($c, 7) * $ok * (61 - 479 * pow($t, 2) + 179 * pow($t, 4) - pow($t, 6)) / 5040;
  109. $result->x = self::$fe + $strf + $dlam * $t6 + pow($dlam, 3) * $t7 + pow($dlam, 5) * $t8 + pow($dlam, 7) * $t9;
  110. $result->y = $nfn + $t1 + pow($dlam, 2) * $t2 + pow($dlam, 4) * $t3 + pow($dlam, 6) * $t4 + pow($dlam, 8) * $t5;
  111. return $result;
  112. }
  113. private static function PuwgToLonLat ($a, $f, $x, $y, $proj) {
  114. $result = new StdClass();
  115. $ok = 0.999923;
  116. if ($proj == 1) $ok = 0.9993;
  117. $recf = 1 / $f;
  118. $b = $a * ($recf - 1) / $recf;
  119. $eSquared = self::CalculateESquared($a, $b);
  120. $e2Squared = self::CalculateE2Squared($a, $b);
  121. $tn = ($a - $b) / ($a + $b);
  122. $ap = $a * (1 - $tn + 5 * (pow($tn, 2) - pow($tn, 3)) / 4 + 81 * (pow($tn, 4) - pow($tn, 5)) / 64);
  123. $bp = 3 * $a * ($tn - pow($tn, 2) + 7 * (pow($tn, 3) - pow($tn, 4)) / 8 + 55 * pow($tn, 5) / 64) / 2;
  124. $cp = 15 * $a * (pow($tn, 2) - pow($tn, 3) + 3 * (pow($tn, 4) - pow($tn, 5)) / 4) / 16;
  125. $dp = 35 * $a * (pow($tn, 3) - pow($tn, 4) + 11 * pow($tn, 5) / 16) / 48;
  126. $ep = 315 * $a * (pow($tn, 4) - pow($tn, 5)) / 512;
  127. if ($proj == 1) {
  128. $olam = 19 * M_PI / 180;
  129. $strf = 0;
  130. $nfn = -5300000;
  131. } else {
  132. $nfn = 0;
  133. $strf = floor($x / 1000000) * 1000000;
  134. $olam = $strf / 60000000 * M_PI;
  135. }
  136. $tmd = ($y - $nfn) / $ok;
  137. $sr = self::sphsr($a, $eSquared, 0);
  138. $ftphi = $tmd / $sr;
  139. for ($i = 0; $i < 5; $i++) {
  140. $t10 = self::sphtmd($ap, $bp, $cp, $dp, $ep, $ftphi);
  141. $sr = self::sphsr($a, $eSquared, $ftphi);
  142. $ftphi = $ftphi + ($tmd - $t10) / $sr;
  143. }
  144. $sr = self::sphsr($a, $eSquared, $ftphi);
  145. $sn = self::sphsn($a, $eSquared, $ftphi);
  146. $s = sin($ftphi);
  147. $c = cos($ftphi);
  148. $t = $s / $c;
  149. $eta = $e2Squared * pow($c, 2);
  150. $de = $x - self::$fe - $strf;
  151. $t10 = $t / (2 * $sr * $sn * pow($ok, 2));
  152. $t11 = $t * (5 + 3 * pow($t, 2) + $eta - 4 * pow($eta, 2) - 9 * pow($t, 2) * $eta) / (24 * $sr * pow($sn, 3) * pow($ok, 4));
  153. $t12 = $t * (61 + 90 * pow($t, 2) + 46 * $eta + 45 * pow($t, 4) - 252 * pow($t, 2) * $eta - 3 * pow($eta, 2) + 100 * pow($eta, 3) - 66 * pow($t, 2) * pow($eta, 2) - 90 * pow($t, 4) * $eta + 88 * pow($eta, 4) + 225 * pow($t, 4) * pow($eta, 2) + 84 * pow($t, 2) * pow($eta, 3) - 192 * pow($t, 2) * pow($eta, 4)) / (720 * $sr * pow($sn, 5) * pow($ok, 6));
  154. $t13 = $t * (1385 + 3633 * pow($t, 2) + 4095 * pow($t, 4) + 1575 * pow($t, 6)) / (40320 * $sr * pow($sn, 7) * pow($ok, 8));
  155. $t14 = 1 / ($sn * $c * $ok);
  156. $t15 = (1 + 2 * pow($t, 2) + $eta) / (6 * pow($sn, 3) * $c * pow($ok, 3));
  157. $t16 = 1 * (5 + 6 * $eta + 28 * pow($t, 2) - 3 * pow($eta, 2) + 8 * pow($t, 2) * $eta + 24 * pow($t, 4) - 4 * pow($eta, 3) + 4 * pow($t, 2) * pow($eta, 2) + 24 * pow($t, 2) * pow($eta, 3)) / (120 * pow($sn, 5) * $c * pow($ok, 5));
  158. $t17 = 1 * (61 + 662 * pow($t, 2) + 1320 * pow($t, 4) + 720 * pow($t, 6)) / (5040 * pow($sn, 7) * $c * pow($ok, 7));
  159. $dlam = $de * $t14 - pow($de, 3) * $t15 + pow($de, 5) * $t16 - pow($de, 7) * $t17;
  160. $result->x = ($olam + $dlam) * 180 / M_PI;
  161. $result->y = ($ftphi - pow($de, 2) * $t10 + pow($de, 4) * $t11 - pow($de, 6) * $t12 + pow($de, 8) * $t13) * 180 / M_PI;
  162. return $result;
  163. }
  164. public static function getEpsgPuwg2000($x, $y = 0) {
  165. if ($x < 13.5 || $x >= 25.5) throw new Exception("Wrong longitude - {$x}");
  166. return floor(($x + 1.5) / 3) + 2171;
  167. }
  168. public static function Wgs84ToPuwg2000($x, $y) {
  169. $result = self::LonLatToPuwg(6378137, 1 / 298.257223563, $x, $y, 4);
  170. $result->epsg = self::getEpsgPuwg2000($x);
  171. return $result;
  172. }
  173. public static function Puwg2000ToWgs84($x, $y) {
  174. $result = self::PuwgToLonLat(6378137, 1 / 298.257223563, $x, $y, 4);
  175. $result->epsg = self::getEpsgPuwg2000($result->x);
  176. return $result;
  177. }
  178. public static function Wgs84ToEpsg2180($x, $y) {
  179. // Parametry elipsoidy GRS-80i
  180. $e = 0.0818191910428; //pierwszy mimośród elipsoidy
  181. $R0 = 6367449.14577; //promieñ sfery Lagrange'a
  182. $Snorm = 0.000002; //parametr normujący
  183. $xo = 5760000; //parametr centrujący
  184. //Współczynniki wielomianu
  185. $a0 = 5765181.11148097;
  186. $a1 = 499800.81713800;
  187. $a2 = -63.81145283;
  188. $a3 = 0.83537915;
  189. $a4 = 0.13046891;
  190. $a5 = -0.00111138;
  191. $a6 = -0.00010504;
  192. // Parametry odwzorowania Gaussa-Kruegera dla układu PUWG92
  193. $L0_stopnie = 19; //Początek układu wsp. PUWG92 (długość)
  194. $m0 = 0.9993;
  195. $x0 = -5300000;
  196. $y0 = 500000;
  197. // Zakres stosowalności metody
  198. $Bmin = 48 * M_PI / 180;
  199. $Bmax = 56 * M_PI / 180;
  200. $dLmin = -6 * M_PI / 180;
  201. $dLmax = 6 * M_PI / 180;
  202. // Weryfikacja danych wejściowych
  203. $B = $y * M_PI / 180;
  204. $dL_stopnie = $x - $L0_stopnie;
  205. $dL = $dL_stopnie * M_PI / 180;
  206. if ($B < $Bmin || $B > $Bmax) throw new Exception("Wrong lattitude - {$y}");
  207. if ($dL < $dLmin || $dL > $dLmax) throw new Exception("Wrong longitude - {$x}");
  208. //etap I - elipsoida na kulę
  209. $U = 1 - $e * sin($B);
  210. $V = 1 + $e * sin($B);
  211. $K = pow(($U /$V), ($e / 2));
  212. $C = $K * tan($B / 2 + M_PI / 4);
  213. $fi = 2 * atan($C) - M_PI / 2;
  214. $d_lambda = $dL;
  215. // etap II - kula na walec
  216. $p = sin($fi);
  217. $q = cos($fi) * cos($d_lambda);
  218. $r = 1 + cos($fi) * sin($d_lambda);
  219. $s = 1 - cos($fi) * sin($d_lambda);
  220. $XMERC = $R0 * atan($p / $q);
  221. $YMERC = 0.5 * $R0 * log($r / $s);
  222. //etap III - walec na płaszczyznę
  223. $Z = new Complex(($XMERC - $xo) * $Snorm, $YMERC * $Snorm);
  224. $Zgk = (new Complex())->add($a6)->multiply($Z)->add($a5)->multiply($Z)->add($a4)->multiply($Z)->add($a3)->multiply($Z)->add($a2)->multiply($Z)->add($a1)->multiply($Z)->add($a0);
  225. $Xgk = $Zgk->real();
  226. $Ygk = $Zgk->imag();
  227. //Przejście do układu aplikacyjnego
  228. $result = new StdClass();
  229. $result->x = $m0 * $Xgk + $x0;
  230. $result->y = $m0 * $Ygk + $y0;
  231. $result->epsg = 2180;
  232. return $result;
  233. }
  234. public static function Wgs84ToPuwg1992($x, $y) {
  235. return self::Wgs84ToEpsg2180($x, $y);
  236. }
  237. public static function Epsg2180ToWgs84($x, $y) {
  238. $L0_stopnie = 19; //Początek układu wsp. PUWG92 (długość)
  239. $m0 = 0.9993;
  240. $x0 = -5300000;
  241. $y0 = 500000;
  242. $R0 = 6367449.14577; //promieñ sfery Lagrange'a
  243. $Snorm = 0.000002; //parametr normujący
  244. $xo_prim=5765181.11148097; //parametr centrujący
  245. // Współczynniki wielomianu
  246. $b0 = 5760000;
  247. $b1 = 500199.26224125;
  248. $b2 = 63.88777449;
  249. $b3 = -0.82039170;
  250. $b4 = -0.13125817;
  251. $b5 = 0.00101782;
  252. $b6 = 0.00010778;
  253. // Współczynniki szeregu tryg.
  254. $c2 = 0.0033565514856;
  255. $c4 = 0.0000065718731;
  256. $c6 = 0.0000000176466;
  257. $c8 = 0.0000000000540;
  258. //Przejście z układu aplikacyjnego
  259. $Xgk = ($x - $x0) / $m0;
  260. $Ygk = ($y - $y0) / $m0;
  261. //etap I - (Xgk, Ygk) -> (Xmerc, Ymerc)
  262. $Z = new Complex(($Xgk - $xo_prim) * $Snorm, $Ygk * $Snorm);
  263. $Zmerc = (new Complex())->add($b6)->multiply($Z)->add($b5)->multiply($Z)->add($b4)->multiply($Z)->add($b3)->multiply($Z)->add($b2)->multiply($Z)->add($b1)->multiply($Z)->add($b0);
  264. $Xmerc = $Zmerc->real();
  265. $Ymerc = $Zmerc->imag();
  266. //etap II - Xmerc,Ymerc -> fi, delta_lambda
  267. $alfa = $Xmerc / $R0;
  268. $beta = $Ymerc / $R0;
  269. $w = 2 * atan(exp($beta)) - M_PI / 2;
  270. $fi = asin(cos($w) * sin($alfa));
  271. $d_lambda = atan(tan($w) / cos($alfa));
  272. //etap III
  273. $B = $fi + $c2 * sin(2 * $fi) + $c4 * sin(4 *$fi) + $c6 * sin(6 * $fi) + $c8 * sin(8 * $fi);
  274. $dL = $d_lambda;
  275. //Obliczenia koncowe
  276. $result = new StdClass();
  277. $result->x = $dL / M_PI * 180 + $L0_stopnie;
  278. $result->y = $B / M_PI * 180;
  279. $result->epsg = 2180;
  280. return $result;
  281. }
  282. public static function Puwg1992ToWgs84($x, $y) {
  283. return self::Epsg2180ToWgs84($x, $y);
  284. }
  285. public static function GetZByEpsg2180($x, $y) {
  286. if (!(is_numeric($x) && is_numeric($y))) throw new Exception('Bad argument(s)');
  287. $table = 'CODGIK_NMT_100_EPSG2180';
  288. //$query = "select x(`the_geom`) as `x`, y(`the_geom`) as `y`, `z` from `{$table}` where abs(x(`the_geom`) - {$x}) < 100 and abs(y(`the_geom`) - {$y}) < 100";
  289. $x1 = round(floor($x / 100) * 100);
  290. $x2 = round(ceil($x / 100) * 100);
  291. $y1 = round(floor($y / 100) * 100);
  292. $y2 = round(ceil($y / 100) * 100);
  293. $query = "select `x`, `y`, `z` from `{$table}` where (`x` = {$x1} and `y` = {$y1}) or (`x` = {$x1} and `y` = {$y2}) or (`x` = {$x2} and `y` = {$y1}) or (`x` = {$x2} and `y` = {$y2})";
  294. try {
  295. $result = DB::getPDO()->fetchAll($query);
  296. } catch (Exception $e) {
  297. throw new Exception('Error while connecting to database');
  298. }
  299. $count = count($result);
  300. if (!$count) throw new Exception('Out of the area');
  301. $z = [];
  302. foreach ($result as $row) {
  303. $z[$row['x']][$row['y']] = $row['z'];
  304. $_x[$row['x']] = true;
  305. $_y[$row['y']] = true;
  306. }
  307. $xmin = min(array_keys($_x));
  308. $xmax = max(array_keys($_x));
  309. $ymin = min(array_keys($_y));
  310. $ymax = max(array_keys($_y));
  311. if ($count == 1) {
  312. return $z[$xmin][$ymin];
  313. } elseif ($count == 2) {
  314. if ($xmin == $xmax && $ymax - $ymin == 100) {
  315. return (($y - $ymin) * $z[$xmin][$ymax] + ($ymax - $y) * $z[$xmin][$ymin]) / 100;
  316. } elseif ($ymin == $ymax && $xmax - $xmin == 100) {
  317. return (($x - $xmin) * $z[$xmax][$ymin] + ($xmax - $x) * $z[$xmin][$ymin]) / 100;
  318. } else throw new Exception('Unknown error #2');
  319. } elseif ($count == 4) {
  320. if (!($ymax - $ymin == 100 && $xmax - $xmin == 100)) throw new Exception('Unknown error #3');
  321. return (($y - $ymin) * (($x - $xmin) * $z[$xmax][$ymax] + ($xmax - $x) * $z[$xmin][$ymax])
  322. + ($ymax - $y) * (($x - $xmin) * $z[$xmax][$ymin] + ($xmax - $x) * $z[$xmin][$ymin])) / 10000;
  323. } else throw new Exception('Unknown error #1');
  324. }
  325. public static function GetZByWgs84($x, $y) {
  326. $epsg2180 = self::Wgs84ToEpsg2180($x, $y);
  327. return self::GetZByEpsg2180($epsg2180->x, $epsg2180->y);
  328. }
  329. }