Completed
Push — master ( 990a68...862b39 )
by Yannick
13:09
created

Elevation::getElevationAtPosition()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 27
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 20
nc 6
nop 3
dl 0
loc 27
rs 8.439
c 0
b 0
f 0
1
<?php
2
require_once(dirname(__FILE__).'/class.Common.php');
3
/*
4
Copyright 2017 Jozef Môstka <[email protected]>
5
6
Licensed under the Apache License, Version 2.0 (the "License");
7
you may not use this file except in compliance with the License.
8
You may obtain a copy of the License at
9
10
    http://www.apache.org/licenses/LICENSE-2.0
11
12
Unless required by applicable law or agreed to in writing, software
13
distributed under the License is distributed on an "AS IS" BASIS,
14
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
See the License for the specific language governing permissions and
16
limitations under the License.
17
*/
18
/*
19
Modified in 2017 by Ycarus <[email protected]>
20
Original version come from https://github.com/tito10047/hgt-reader
21
*/
22
23
class Elevation {
24
	private $htgFilesDestination;
25
	private $resolution  = -1;
26
	private $measPerDeg;
27
	private $openedFiles = [];
28
29
	public function __construct($htgFilesDestination = '', $resolution = 3) {
30
		if ($htgFilesDestination == '') $htgFilesDestination = dirname(__FILE__).'/../install/tmp/';
31
		$this->htgFilesDestination = $htgFilesDestination;
32
		$this->resolution          = $resolution;
33
		switch ($resolution) {
34
			case 1:
35
				$this->measPerDeg = 3601;
36
				break;
37
			case 3:
38
				$this->measPerDeg = 1201;
39
				break;
40
			default:
41
				throw new \Exception("bad resolution can be only one of 1,3");
42
		}
43
		register_shutdown_function(function () {
44
			$this->closeAllFiles();
45
		});
46
	}
47
48
	public function closeAllFiles() {
49
		foreach ($this->openedFiles as $file) {
50
			fclose($file);
51
		}
52
		$this->openedFiles = [];
53
	}
54
55
	private function getElevationAtPosition($fileName, $row, $column) {
56
		if (!array_key_exists($fileName, $this->openedFiles)) {
57
			if (!file_exists($this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName)) {
58
				throw new \Exception("File '{$fileName}' not exists.");
59
			}
60
			$file = fopen($this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName, "r");
61
			if ($file === false) {
62
				throw new \Exception("Cant open file '{$fileName}' for reading.");
63
			}
64
			$this->openedFiles[$fileName] = $file;
65
		} else {
66
			$file = $this->openedFiles[$fileName];
67
		}
68
69
		if ($row > $this->measPerDeg || $column > $this->measPerDeg) {
70
			//TODO:open next file
71
			throw new \Exception("Mot implemented yet");
72
		}
73
		$aRow     = $this->measPerDeg - $row;
74
		$position = ($this->measPerDeg * ($aRow - 1)) + $column;
75
		$position *= 2;
76
		fseek($file, $position);
77
		$short  = fread($file, 2);
78
		$_      = unpack("n*", $short);
79
		$shorts = reset($_);
80
		return $shorts;
81
	}
82
83
	/**
84
	 * @param float $lat
85
	 * @param float $lon
86
	 * @param null  $fName
87
	 *
88
	 * @return mixed
89
	 * @throws \Exception
90
	 */
91
	public function getElevation($lat, $lon, &$fName = null) {
92
		if ($this->resolution == -1) {
93
			throw new \Exception("use HgtReader::init(ASSETS_HGT . DIRECTORY_SEPARATOR, 3);");
94
		}
95
		$N      = $this->getDeg($lat, 2);
96
		$E      = $this->getDeg($lon, 3);
97
		$fName  = "N{$N}E{$E}.hgt";
98
		
99
		$latSec = $this->getSec($lat);
100
		$lonSec = $this->getSec($lon);
101
102
		$Xn = round($latSec / $this->resolution, 3);
103
		$Yn = round($lonSec / $this->resolution, 3);
104
105
		$a1 = round($Xn);
106
		$a2 = round($Yn);
107
108
		if ($Xn <= $a1 && $Yn <= $a2) {
109
			$b1 = $a1 - 1;
110
			$b2 = $a2;
111
			$c1 = $a1;
112
			$c2 = $a2 - 1;
113
		} else if ($Xn >= $a1 && $Yn >= $a2) {
114
			$b1 = $a1 + 1;
115
			$b2 = $a2;
116
			$c1 = $a1;
117
			$c2 = $a2 + 1;
118
		} else if ($Xn > $a1 && $Yn < $a2) {
119
			$b1 = $a1;
120
			$b2 = $a2 - 1;
121
			$c1 = $a1 + 1;
122
			$c2 = $a2;
123
		} else if ($Xn < $a1 && $Yn > $a2) {
124
			$b1 = $a1 - 1;
125
			$b2 = $a2;
126
			$c1 = $a1;
127
			$c2 = $a2 + 1;
128
		} else {
129
			throw new \Exception("{$Xn}:{$Yn}");
130
		}
131
		$a3 = $this->getElevationAtPosition($fName, $a1, $a2);
132
		$b3 = $this->getElevationAtPosition($fName, $b1, $b2);
133
		$c3 = $this->getElevationAtPosition($fName, $c1, $c2);
134
135
		$n1 = ($c2 - $a2) * ($b3 - $a3) - ($c3 - $a3) * ($b2 - $a2);
136
		$n2 = ($c3 - $a3) * ($b1 - $a1) - ($c1 - $a1) * ($b3 - $a3);
137
		$n3 = ($c1 - $a1) * ($b2 - $a2) - ($c2 - $a2) * ($b1 - $a1);
138
139
		$d  = -$n1 * $a1 - $n2 * $a2 - $n3 * $a3;
140
		$zN = (-$n1 * $Xn - $n2 * $Yn - $d) / $n3;
141
142
		return $zN;
143
	}
144
145
	private function getDeg($deg, $numPrefix) {
146
		$deg = abs($deg);
147
		$d   = floor($deg);     // round degrees
148
		if ($numPrefix >= 3) {
149
			if ($d < 100) {
150
				$d = '0' . $d;
151
			}
152
		} // pad with leading zeros
153
		if ($d < 10) {
154
			$d = '0' . $d;
155
		}
156
		return $d;
157
	}
158
159
	private function getSec($deg) {
160
		$deg = abs($deg);
161
		$sec = round($deg * 3600, 4);
162
		$m   = fmod(floor($sec / 60), 60);
163
		$s   = round(fmod($sec, 60), 4);
164
		return ($m * 60) + $s;
165
	}
166
167
	public function download($lat,$lon) {
168
		$N      = $this->getDeg($lat, 2);
169
		$E      = $this->getDeg($lon, 3);
170
		$fileName  = "N{$N}E{$E}.hgt";
171
		if (!file_exists($this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName)) {
172
			$Common = new Common();
173
			$Common->download('https://s3.amazonaws.com/elevation-tiles-prod/skadi/N'.$N.'/'.$fileName.'.gz',$this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName . '.gz');
174
			if (!file_exists($this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName . '.gz')) {
175
				throw new \Exception("File '{$fileName}.gz' not exists.");
176
			}
177
			$Common->gunzip($this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName . '.gz',$this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName);
0 ignored issues
show
Bug introduced by
The method gunzip() does not seem to exist on object<Common>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
178
			unlink($this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName . '.gz');
179
		}
180
		return true;
181
	}
182
}
183
/*
184
$lat = 46.3870;
185
$lon = 5.2941;
186
$Elevation = new Elevation();
187
$Elevation->download($lat,$lon);
188
echo($Elevation->getElevation($lat,$lon));
189
*/