Completed
Push — master ( e8d7a9...7fe401 )
by Yannick
31:55
created

Elevation   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 210
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 0
loc 210
rs 8.3396
c 0
b 0
f 0
wmc 44
lcom 1
cbo 2

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 18 4
A closeAllFiles() 0 6 2
B getElevationAtPosition() 0 28 6
C getElevation() 0 62 12
A getDeg() 0 13 4
A getSec() 0 7 1
D download() 0 28 10
B downloadNeeded() 0 26 5

How to fix   Complexity   

Complex Class

Complex classes like Elevation often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Elevation, and based on these observations, apply Extract Interface, too.

1
<?php
2
require_once(dirname(__FILE__).'/class.Common.php');
3
require_once(dirname(__FILE__).'/class.Connection.php');
4
/*
5
Copyright 2017 Jozef Môstka <[email protected]>
6
7
Licensed under the Apache License, Version 2.0 (the "License");
8
you may not use this file except in compliance with the License.
9
You may obtain a copy of the License at
10
11
    http://www.apache.org/licenses/LICENSE-2.0
12
13
Unless required by applicable law or agreed to in writing, software
14
distributed under the License is distributed on an "AS IS" BASIS,
15
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
See the License for the specific language governing permissions and
17
limitations under the License.
18
*/
19
/*
20
Modified in 2017 by Ycarus <[email protected]>
21
Original version come from https://github.com/tito10047/hgt-reader
22
*/
23
24
class Elevation {
25
	private $htgFilesDestination;
26
	private $resolution  = -1;
27
	private $measPerDeg;
28
	private $openedFiles = [];
29
30
	public function __construct($htgFilesDestination = '', $resolution = 3) {
31
		if ($htgFilesDestination == '') $htgFilesDestination = dirname(__FILE__).'/../data/';
32
		$this->htgFilesDestination = $htgFilesDestination;
33
		$this->resolution          = $resolution;
34
		switch ($resolution) {
35
			case 1:
36
				$this->measPerDeg = 3601;
37
				break;
38
			case 3:
39
				$this->measPerDeg = 1201;
40
				break;
41
			default:
42
				throw new \Exception("bad resolution can be only one of 1,3");
43
		}
44
		register_shutdown_function(function () {
45
			$this->closeAllFiles();
46
		});
47
	}
48
49
	public function closeAllFiles() {
50
		foreach ($this->openedFiles as $file) {
51
			fclose($file);
52
		}
53
		$this->openedFiles = [];
54
	}
55
56
	private function getElevationAtPosition($fileName, $row, $column) {
57
		if (!array_key_exists($fileName, $this->openedFiles)) {
58
			if (!file_exists($this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName)) {
59
				throw new \Exception("File '{$fileName}' not exists.");
60
			}
61
			$file = fopen($this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName, "r");
62
			if ($file === false) {
63
				throw new \Exception("Cant open file '{$fileName}' for reading.");
64
			}
65
			$this->openedFiles[$fileName] = $file;
66
		} else {
67
			$file = $this->openedFiles[$fileName];
68
		}
69
70
		if ($row > $this->measPerDeg || $column > $this->measPerDeg) {
71
			//TODO:open next file
72
			throw new \Exception("Not implemented yet");
73
		}
74
		$aRow     = $this->measPerDeg - $row;
75
		$position = ($this->measPerDeg * ($aRow - 1)) + $column;
76
		$position *= 2;
77
		fseek($file, $position);
78
		$short  = fread($file, 2);
79
		$_      = unpack("n*", $short);
80
		$shorts = reset($_);
81
		echo $shorts."\n";
82
		return $shorts;
83
	}
84
85
	/**
86
	 * @param float $lat
87
	 * @param float $lon
88
	 * @param null  $fName
89
	 *
90
	 * @return mixed
91
	 * @throws \Exception
92
	 */
93
	public function getElevation($lat, $lon, &$fName = null) {
94
		if ($this->resolution == -1) {
95
			throw new \Exception("use HgtReader::init(ASSETS_HGT . DIRECTORY_SEPARATOR, 3);");
96
		}
97
		if ($lat < 0) {
98
			$latd = 'S'.$this->getDeg($lat, 2);
99
		} else {
100
			$latd = 'N'.$this->getDeg($lat, 2);
101
		}
102
		if ($lon < 0) {
103
			$lond = 'W'.$this->getDeg($lon, 3);
104
		} else {
105
			$lond = 'W'.$this->getDeg($lon, 3);
106
		}
107
		$fName  = $latd.$lond.".hgt";
108
109
		
110
		$latSec = $this->getSec($lat);
111
		$lonSec = $this->getSec($lon);
112
113
		$Xn = round($latSec / $this->resolution, 3);
114
		$Yn = round($lonSec / $this->resolution, 3);
115
116
		$a1 = round($Xn);
117
		$a2 = round($Yn);
118
119
		if ($Xn <= $a1 && $Yn <= $a2) {
120
			$b1 = $a1 - 1;
121
			$b2 = $a2;
122
			$c1 = $a1;
123
			$c2 = $a2 - 1;
124
		} else if ($Xn >= $a1 && $Yn >= $a2) {
125
			$b1 = $a1 + 1;
126
			$b2 = $a2;
127
			$c1 = $a1;
128
			$c2 = $a2 + 1;
129
		} else if ($Xn > $a1 && $Yn < $a2) {
130
			$b1 = $a1;
131
			$b2 = $a2 - 1;
132
			$c1 = $a1 + 1;
133
			$c2 = $a2;
134
		} else if ($Xn < $a1 && $Yn > $a2) {
135
			$b1 = $a1 - 1;
136
			$b2 = $a2;
137
			$c1 = $a1;
138
			$c2 = $a2 + 1;
139
		} else {
140
			throw new \Exception("{$Xn}:{$Yn}");
141
		}
142
		$a3 = $this->getElevationAtPosition($fName, $a1, $a2);
143
		$b3 = $this->getElevationAtPosition($fName, $b1, $b2);
144
		$c3 = $this->getElevationAtPosition($fName, $c1, $c2);
145
146
		$n1 = ($c2 - $a2) * ($b3 - $a3) - ($c3 - $a3) * ($b2 - $a2);
147
		$n2 = ($c3 - $a3) * ($b1 - $a1) - ($c1 - $a1) * ($b3 - $a3);
148
		$n3 = ($c1 - $a1) * ($b2 - $a2) - ($c2 - $a2) * ($b1 - $a1);
149
150
		$d  = -$n1 * $a1 - $n2 * $a2 - $n3 * $a3;
151
		$zN = (-$n1 * $Xn - $n2 * $Yn - $d) / $n3;
152
153
		return $zN;
154
	}
155
156
	private function getDeg($deg, $numPrefix) {
157
		$deg = abs($deg);
158
		$d   = floor($deg);     // round degrees
159
		if ($numPrefix >= 3) {
160
			if ($d < 100) {
161
				$d = '0' . $d;
162
			}
163
		} // pad with leading zeros
164
		if ($d < 10) {
165
			$d = '0' . $d;
166
		}
167
		return $d;
168
	}
169
170
	private function getSec($deg) {
171
		$deg = abs($deg);
172
		$sec = round($deg * 3600, 4);
173
		$m   = fmod(floor($sec / 60), 60);
174
		$s   = round(fmod($sec, 60), 4);
175
		return ($m * 60) + $s;
176
	}
177
178
	public function download($lat,$lon, $debug = false) {
179
		if ($lat < 0) {
180
			$latd = 'S'.$this->getDeg($lat, 2);
181
		} else {
182
			$latd = 'N'.$this->getDeg($lat, 2);
183
		}
184
		if ($lon < 0) {
185
			$lond = 'W'.$this->getDeg($lon, 3);
186
		} else {
187
			$lond = 'W'.$this->getDeg($lon, 3);
188
		}
189
		$fileName  = $latd.$lond.".hgt";
190
		if (!file_exists($this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName)) {
191
			$Common = new Common();
192
			if ($debug) echo 'Downloading '.$fileName.'.gz ...';
193
			$Common->download('https://s3.amazonaws.com/elevation-tiles-prod/skadi/'.$latd.'/'.$fileName.'.gz',$this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName . '.gz');
194
			if (!file_exists($this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName . '.gz')) {
195
				if ($debug) echo "File '{$fileName}.gz' not exists.";
196
				return false;
197
			}
198
			if ($debug) echo 'Done'."\n";
199
			if ($debug) echo 'Decompress '.$fileName.' ....';
200
			$Common->gunzip($this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName . '.gz',$this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName);
201
			if ($debug) echo 'Done'."\n";
202
			unlink($this->htgFilesDestination . DIRECTORY_SEPARATOR . $fileName . '.gz');
203
		}
204
		return true;
205
	}
206
	
207
	public function downloadNeeded() {
208
		$Connection = new Connection();
209
		$db = $Connection->db;
210
		$query = 'SELECT latitude, longitude FROM spotter_output WHERE latitude <> 0 AND longitude <> 0 ORDER BY date DESC LIMIT 10';
211
		$query_values = array();
212
		try {
213
			$sth = $db->prepare($query);
214
			$sth->execute($query_values);
215
		} catch(PDOException $e) {
216
			return "error : ".$e->getMessage();
217
		}
218
		while ($data = $sth->fetch(PDO::FETCH_ASSOC)) {
219
			$this->download($data['latitude'],$data['longitude'],true);
220
		}
221
		$query = 'SELECT latitude, longitude FROM tracker_output WHERE latitude <> 0 AND longitude <> 0 ORDER BY date DESC LIMIT 10';
222
		$query_values = array();
223
		try {
224
			$sth = $db->prepare($query);
225
			$sth->execute($query_values);
226
		} catch(PDOException $e) {
227
			return "error : ".$e->getMessage();
228
		}
229
		while ($data = $sth->fetch(PDO::FETCH_ASSOC)) {
230
			$this->download($data['latitude'],$data['longitude'],true);
231
		}
232
	}
233
}
234
/*
235
$lat = 38.40207;
236
$lon = -11.273;
237
$Elevation = new Elevation();
238
$Elevation->download($lat,$lon);
239
echo($Elevation->getElevation($lat,$lon));
240
*/
241
/*
242
$Elevation = new Elevation();
243
echo $Elevation->downloadNeeded();
244
*/