Sjtsk1   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 185
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 134
c 1
b 0
f 0
dl 0
loc 185
ccs 133
cts 133
cp 1
rs 10
wmc 12

6 Methods

Rating   Name   Duplication   Size   Complexity  
A toSJTSKLatLong() 0 47 1
A toLonLat() 0 6 3
A __construct() 0 4 3
B fromLonLat() 0 83 3
A sqr() 0 3 1
A toWSG84LatLong() 0 16 1
1
<?php
2
3
namespace kalanis\kw_coordinates\Codecs;
4
5
6
use kalanis\kw_coordinates\Interfaces;
7
use kalanis\kw_coordinates\Support;
8
9
10
/**
11
 * Class Sjtsk1
12
 * @package kalanis\kw_coordinates\Codecs
13
 * @link https://blog.drndos.sk/2013/03/how-to-convert-s-jtsk-coordinates-to-wsg84/
14
 * @link https://www.pecina.cz/krovak.html
15
 *
16
 * SJTSKtoWSG84.java Filip Bednárik <[email protected]>
17
 * package sk.datalan.semweb.czechpediacrawler;
18
 *
19
 * toWgs is port from java class
20
 * fromWgs is port from JavaScript code
21
 *
22
 * Do not ask me how both works...; but used, tested and works
23
 */
24
class Sjtsk1 implements Interfaces\ICodecs
25
{
26
    const FG_SHIFT = 17.66666666666666;
27
    const dX_SHIFT = 589;
28
    const dY_SHIFT = 76;
29
    const dZ_SHIFT = 480;
30
31
    protected Interfaces\INumbers $pos;
32
    protected Interfaces\IFormatted $out;
33
34 4
    public function __construct(?Interfaces\INumbers $position = null, ?Interfaces\IFormatted $output = null)
35
    {
36 4
        $this->pos = $position ?: new Support\Position();
37 4
        $this->out = $output ?: new Support\JtskObject();
38 4
    }
39
40 2
    public function fromLonLat(Interfaces\INumbers $position, array $params): Interfaces\IFormatted
41
    {
42 2
        $d2r = pi() / 180;
43 2
        $a = 6378137.0;
44 2
        $f1 = 298.257223563;
45 2
        $dx = -570.69;
46 2
        $dy = -85.69;
47 2
        $dz = -462.84;
48 2
        $wx = 4.99821 / 3600 * pi() / 180;
49 2
        $wy = 1.58676 / 3600 * pi() / 180;
50 2
        $wz = 5.2611 / 3600 * pi() / 180;
51 2
        $m = -3.543e-6;
52
53 2
        $B = $position->getLatitude() * $d2r;
54 2
        $L = $position->getLongitude() * $d2r;
55 2
        $H = $position->getAltitude();
56
57 2
        $e2 = 1 - $this->sqr(1 - (1 / $f1));
58 2
        $rho = $a / sqrt(1 - ($e2 * $this->sqr(sin($B))));
59 2
        $x1 = ($rho + $H) * cos($B) * cos($L);
60 2
        $y1 = ($rho + $H) * cos($B) * sin($L);
61 2
        $z1 = (((1 - $e2) * $rho) + $H) * sin($B);
62
63 2
        $x2 = $dx + (1 + $m) * ($x1 + ($wz * $y1) - ($wy * $z1));
64 2
        $y2 = $dy + (1 + $m) * (((-$wz) * $x1) + $y1 + ($wx * $z1));
65 2
        $z2 = $dz + (1 + $m) * (($wy * $x1) - ($wx * $y1) + $z1);
66
67 2
        $a = 6377397.15508;
68 2
        $f1 = 299.152812853;
69 2
        $ab = $f1 / ($f1 - 1);
70 2
        $p = sqrt($this->sqr($x2) + $this->sqr($y2));
71 2
        $e2 = 1 - $this->sqr(1 - (1 / $f1));
72 2
        $th = atan(($z2 * $ab) / $p);
73 2
        $st = sin($th);
74 2
        $ct = cos($th);
75 2
        $t = ($z2 + ($e2 * $ab * $a * ($st * $st * $st))) / ($p - ($e2 * $a * ($ct * $ct * $ct)));
76
77 2
        $B = atan($t);
78 2
        $H = sqrt(1 + ($t * $t)) * ($p - ($a / sqrt(1 + ((1 - $e2) * $t * $t))));
79 2
        $L = 2 * atan($y2 / ($p + $x2));
80
81 2
        $a = 6377397.15508;
0 ignored issues
show
Unused Code introduced by
The assignment to $a is dead and can be removed.
Loading history...
82 2
        $e = 0.081696831215303;
83 2
        $n = 0.97992470462083;
84 2
        $rho0 = 12310230.12797036;
85 2
        $sinUQ = 0.863499969506341;
86 2
        $cosUQ = 0.504348889819882;
87 2
        $sinVQ = 0.420215144586493;
88 2
        $cosVQ = 0.907424504992097;
89 2
        $alpha = 1.000597498371542;
90 2
        $k2 = 1.00685001861538;
91
92 2
        $sinB = sin($B);
93 2
        $t = (1 - ($e * $sinB)) / (1 + ($e * $sinB));
94 2
        $t = ($this->sqr(1 + $sinB) / (1 - $this->sqr($sinB))) * exp($e * log($t));
95 2
        $t = $k2 * exp($alpha * log($t));
96
97 2
        $sinU = ($t - 1) / ($t + 1);
98 2
        $cosU = sqrt(1 - ($sinU * $sinU));
99 2
        $V = $alpha * $L;
100 2
        $sinV = sin($V);
101 2
        $cosV = cos($V);
102 2
        $cosDV = ($cosVQ * $cosV) + ($sinVQ * $sinV);
103 2
        $sinDV = ($sinVQ * $cosV) - ($cosVQ * $sinV);
104 2
        $sinS = ($sinUQ * $sinU) + ($cosUQ * $cosU * $cosDV);
105 2
        $cosS = sqrt(1 - $sinS * $sinS);
106 2
        $sinD = ($sinDV * $cosU) / $cosS;
107 2
        $cosD = sqrt(1 - ($sinD * $sinD));
108
109 2
        $eps = $n * atan($sinD / $cosD);
110 2
        $rho = $rho0 * exp(-$n * log((1 + $sinS) / $cosS));
111
112 2
        $CX = $rho * sin($eps);
113 2
        $CY = $rho * cos($eps);
114
115 2
        $obj = clone $this->out;
116
117 2
        $mul = isset($params['czech']) && boolval($params['czech']) ? 1 : -1;
118
119 2
        return $obj->setData(
120 2
            $mul * $CX,
121 2
            $mul * $CY,
122
            $H
123
        );
124
    }
125
126 2
    protected function sqr(float $x): float
127
    {
128 2
        return $x * $x;
129
    }
130
131 2
    public function toLonLat(Interfaces\IFormatted $source, array $params): Interfaces\INumbers
132
    {
133 2
        $mul = isset($params['czech']) && boolval($params['czech']) ? 1 : -1;
134
135 2
        $sjtskLatLong = $this->toSJTSKLatLong($mul * floatval(strval($source->getLatitude())), $mul * floatval(strval($source->getLongitude())));
136 2
        return $this->toWSG84LatLong($sjtskLatLong[0], $sjtskLatLong[1]);
137
    }
138
139
    /**
140
     * @param float $x
141
     * @param float $y
142
     * @return array<float>
143
     */
144 2
    protected function toSJTSKLatLong(float $x, float $y): array
145
    {
146 2
        $finRad = pi() * 49.5 / 180;
147 2
        $la0deg = 42 + 31.00 / 60 + 31.41725 / 3600;
148 2
        $ro1 = sqrt($x * $x + $y * $y);
149 2
        $rGauss = 6380065.5402;
150 2
        $betakv = pi() * 11.5 / 180;
151 2
        $fi0 = 59 + (42.00 / 60) + (42.69689 / 3600);
152 2
        $a = 6377397.155;
153 2
        $b = 6356078.96325;
154
155 2
        $e2 = sqrt(($a * $a - $b * $b) / ($b * $b));
156 2
        $m = cos($betakv);
157 2
        $vn = sqrt(1 + $e2 * $e2 * cos($finRad) * cos($finRad));
158 2
        $gamma = atan2($y, $x);
159 2
        $c = $rGauss * sin($betakv) / $m / pow(tan($betakv / 2), $m);
160
161 2
        $fi0rad = $fi0 * pi() / 180;
162 2
        $fin = atan2(tan($finRad), $vn);
163 2
        $lambv = $gamma / $m;
164 2
        $betav = 2 * atan(pow($ro1 / $c, 1 / $m));
165 2
        $fi = asin(cos($betav) * sin($fi0rad) - sin($betav) * cos($fi0rad) * cos($lambv));
166
167 2
        $n = sin($finRad) / sin($fin);
168 2
        $la = asin(sin($betav) * sin($lambv) / cos($fi));
169 2
        $la0 = $la0deg * pi() / 180;
170
171 2
        $laRad = ($la0 - $la) / $n;
172 2
        $laFerro = $laRad * 180 / pi();
173 2
        $sjtskLong = $laFerro - static::FG_SHIFT;
174 2
        $e1 = sqrt(($a * $a - $b * $b) / ($a * $a));
175
176 2
        $k = tan(pi() / 4 + $fin / 2) / (pow(tan(pi() / 4 + $finRad / 2), $n) * pow((1 - $e1 * sin($finRad)) / (1 + $e1 * sin($finRad)), $n * $e1 / 2));
177 2
        $fik = 2 * atan(pow(1 / $k * tan(pi() / 4 + $fi / 2), 1 / $n)) - pi() / 2;
178 2
        $tga = pow((1 - $e1 * sin($fik)) / (1 + $e1 * sin($fik)), $n * $e1 / 2);
179 2
        $fi1Rad = 2 * atan(pow(1 / $k / $tga * tan(pi() / 4 + $fi / 2), 1 / $n)) - pi() / 2;
180 2
        $tga2 = pow((1 - $e1 * sin($fi1Rad)) / (1 + $e1 * sin($fi1Rad)), $n * $e1 / 2);
181 2
        $fi2Rad = 2 * atan(pow(1 / $k / $tga2 * tan(pi() / 4 + $fi / 2), 1 / $n)) - pi() / 2;
182 2
        $tga3 = pow((1 - $e1 * sin($fi2Rad)) / (1 + $e1 * sin($fi2Rad)), $n * $e1 / 2);
183 2
        $fi3Rad = 2 * atan(pow(1 / $k / $tga3 * tan(pi() / 4 + $fi / 2), 1 / $n)) - pi() / 2;
184 2
        $tga4 = pow((1 - $e1 * sin($fi3Rad)) / (1 + $e1 * sin($fi3Rad)), $n * $e1 / 2);
185 2
        $fi4Rad = 2 * atan(pow(1 / $k / $tga4 * tan(pi() / 4 + $fi / 2), 1 / $n)) - pi() / 2;
186 2
        $tga5 = pow((1 - $e1 * sin($fi4Rad)) / (1 + $e1 * sin($fi4Rad)), $n * $e1 / 2);
187 2
        $firad = 2 * atan(pow(1 / $k / $tga5 * tan(pi() / 4 + $fi / 2), 1 / $n)) - pi() / 2;
188 2
        $sjtskLat = $firad * 180 / pi();
189
190 2
        return [$sjtskLat, $sjtskLong];
191
    }
192
193 2
    protected function toWSG84LatLong(float $SJTSKlat, float $SJTSKlong): Interfaces\INumbers
194
    {
195 2
        $filRad = $SJTSKlat * pi() / 180;
196 2
        $la1Rad = $SJTSKlong * pi() / 180;
197 2
        $a1 = 6377397.155;
198 2
        $f1 = 0.00334277318217481;
199 2
        $a2 = 6378137.00;
200 2
        $f2 = 0.00335281066474748;
201 2
        $e1 = sqrt(2 * $f1 - $f1 * $f1);
202 2
        $M = $a1 * (1 - $e1 * $e1) / pow((1 - $e1 * $e1 * sin($filRad) * sin($filRad)), 1.5);
203 2
        $N = $a1 / sqrt(1 - $e1 * $e1 * sin($filRad) * sin($filRad));
204 2
        $dlasec = ((-1 * static::dX_SHIFT * sin($la1Rad)) + static::dY_SHIFT * cos($la1Rad)) / ($N * cos($filRad) * sin(pi() / 180 / 3600));
205 2
        $dfisec = ((-1 * static::dX_SHIFT * sin($filRad) * cos($la1Rad)) - static::dY_SHIFT * sin($filRad) * sin($la1Rad) + static::dZ_SHIFT * cos($filRad) + ($a1 * ($f2 - $f1) + $f1 * ($a2 - $a1)) * sin(2 * $filRad)) / ($M * sin(pi() / 180 / 3600));
206 2
        $wsgLong = $SJTSKlong + $dlasec / 3600;
207 2
        $wsgLat = $SJTSKlat + $dfisec / 3600;
208 2
        return (clone $this->pos)->setData($wsgLong, $wsgLat);
209
    }
210
}
211