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; |
|
|
|
|
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
|
|
|
|