Skip to content

Commit 720eee3

Browse files
committed
Approximations
1 parent 26ffea0 commit 720eee3

File tree

4 files changed

+121
-14
lines changed

4 files changed

+121
-14
lines changed

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@ See: [http://www2.jpl.nasa.gov/srtm/](http://www2.jpl.nasa.gov/srtm/).
66

77
## Usage:
88

9-
>>> import srtm
10-
>>> elevation_data = srtm.get_data()
11-
>>> print 'CGN Airport elevation (meters):', elevation_data.get_elevation(50.8682, 7.1377)
9+
import srtm
10+
elevation_data = srtm.get_data()
11+
print 'CGN Airport elevation (meters):', elevation_data.get_elevation(50.8682, 7.1377)
12+
13+
With get\_elevation() an elevation of the the nearest location found in the SRTM data will be given.
14+
If you need an approximation based on nearby locations, you can use:
15+
16+
elevation_data.get_elevation(50.8682, 7.1377, approximate=True)
1217

1318
You can create elevation images with:
1419

srtm/data.py

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def __init__(self, srtm1_files, srtm3_files, files_directory):
5252

5353
self.files = {}
5454

55-
def get_elevation(self, latitude, longitude):
55+
def get_elevation(self, latitude, longitude, approximate=None):
5656
geo_elevation_file = self.get_file(float(latitude), float(longitude))
5757

5858
mod_logging.debug('File for ({0}, {1}) -> {2}'.format(
@@ -61,7 +61,10 @@ def get_elevation(self, latitude, longitude):
6161
if not geo_elevation_file:
6262
return None
6363

64-
return geo_elevation_file.get_elevation(float(latitude), float(longitude))
64+
return geo_elevation_file.get_elevation(
65+
float(latitude),
66+
float(longitude),
67+
approximate)
6568

6669
def get_file(self, latitude, longitude):
6770
"""
@@ -79,7 +82,7 @@ def get_file(self, latitude, longitude):
7982
if not data:
8083
return None
8184

82-
result = GeoElevationFile(file_name, data)
85+
result = GeoElevationFile(file_name, data, self)
8386
self.files[file_name] = result
8487
return result
8588

@@ -195,7 +198,12 @@ def get_image(self, size, latitude_interval, longitude_interval, max_elevation,
195198
return image
196199

197200
class GeoElevationFile:
198-
""" Contains data from a single Shuttle elevation file. """
201+
"""
202+
Contains data from a single Shuttle elevation file.
203+
204+
This class hould not be instantiated without its GeoElevationData because
205+
it may need elevations from nearby files.
206+
"""
199207

200208
file_name = None
201209
url = None
@@ -205,9 +213,10 @@ class GeoElevationFile:
205213

206214
data = None
207215

208-
def __init__(self, file_name, data):
216+
def __init__(self, file_name, data, geo_elevation_data):
209217
""" Data is a raw file contents of the file. """
210218

219+
self.geo_elevation_data = geo_elevation_data
211220
self.file_name = file_name
212221

213222
self.parse_file_name_starting_position()
@@ -219,19 +228,66 @@ def __init__(self, file_name, data):
219228

220229
self.square_side = int(square_side)
221230

222-
def get_elevation(self, latitude, longitude):
231+
def get_elevation(self, latitude, longitude, approximate=None):
232+
"""
233+
If approximate is True then only the points from SRTM grid will be
234+
used, otherwise a basic aproximation of nearby points will be calculated.
235+
"""
223236
if not (self.latitude <= latitude < self.latitude + 1):
224237
raise Exception('Invalid latitude %s for file %s' % (latitude, self.file_name))
225238
if not (self.longitude <= longitude < self.longitude + 1):
226239
raise Exception('Invalid longitude %s for file %s' % (longitude, self.file_name))
227240

228241
points = self.square_side ** 2
229242

230-
pdb.set_trace()
231-
row = int(mod_math.floor((self.latitude + 1 - latitude) * float(self.square_side - 1)))
232-
column = int(mod_math.floor((longitude - self.longitude) * float(self.square_side - 1)))
243+
row = mod_math.floor((self.latitude + 1 - latitude) * float(self.square_side - 1))
244+
column = mod_math.floor((longitude - self.longitude) * float(self.square_side - 1))
245+
246+
if approximate:
247+
return self.approximation(latitude, longitude)
248+
else:
249+
return self.get_elevation_from_row_and_column(int(row), int(column))
250+
251+
def approximation(self, latitude, longitude):
252+
"""
253+
Dummy approximation with nearest points. The nearest the neighbour the
254+
more important will be its elevation.
255+
"""
256+
d = 1. / self.square_side
257+
d_meters = d * mod_utils.ONE_DEGREE
233258

234-
return self.get_elevation_from_row_and_column(row, column)
259+
# Since the less the distance => the more important should be the
260+
# distance of the point, we'll use d-distance as importance coef
261+
# here:
262+
importance_1 = d_meters - mod_utils.distance(latitude + d, longitude, latitude, longitude)
263+
elevation_1 = self.geo_elevation_data.get_elevation(latitude + d, longitude, approximate=False)
264+
265+
importance_2 = d_meters - mod_utils.distance(latitude - d, longitude, latitude, longitude)
266+
elevation_2 = self.geo_elevation_data.get_elevation(latitude - d, longitude, approximate=False)
267+
268+
importance_3 = d_meters - mod_utils.distance(latitude, longitude + d, latitude, longitude)
269+
elevation_3 = self.geo_elevation_data.get_elevation(latitude, longitude + d, approximate=False)
270+
271+
importance_4 = d_meters - mod_utils.distance(latitude, longitude - d, latitude, longitude)
272+
elevation_4 = self.geo_elevation_data.get_elevation(latitude, longitude - d, approximate=False)
273+
# TODO(TK) Check if coordinates inside the same file, and only the decide if to xall
274+
# self.geo_elevation_data.get_elevation or just self.get_elevation
275+
276+
# Normalize importance:
277+
sum_importances = float(importance_1 + importance_2 + importance_3 + importance_4)
278+
279+
# Check normallization:
280+
assert abs(importance_1 / sum_importances + \
281+
importance_2 / sum_importances + \
282+
importance_3 / sum_importances + \
283+
importance_4 / sum_importances - 1 ) < 0.000001
284+
285+
result = importance_1 / sum_importances * elevation_1 + \
286+
importance_2 / sum_importances * elevation_2 + \
287+
importance_3 / sum_importances * elevation_3 + \
288+
importance_4 / sum_importances * elevation_4
289+
290+
return result
235291

236292
def get_elevation_from_row_and_column(self, row, column):
237293
i = row * (self.square_side) + column

srtm/utils.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@
1414
# See the License for the specific language governing permissions and
1515
# limitations under the License.
1616

17+
import math as mod_math
18+
19+
ONE_DEGREE = 1000. * 10000.8 / 90.
20+
21+
def distance(latitude_1, longitude_1, latitude_2, longitude_2):
22+
"""
23+
Distance between two points.
24+
"""
25+
26+
coef = mod_math.cos(latitude_1 / 180. * mod_math.pi)
27+
x = latitude_1 - latitude_2
28+
y = (longitude_1 - longitude_2) * coef
29+
30+
return mod_math.sqrt(x * x + y * y) * ONE_DEGREE
31+
1732
def get_color_between(color1, color2, i):
1833
""" i is a number between 0 and 1, if 0 then color1, if 1 color2, ... """
1934
if i <= 0:

test.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def test_invalit_coordinates_for_file(self):
8383
message = str(e)
8484
self.assertEquals('Invalid longitude 1 for file N47E013.hgt', message)
8585

86-
def test_invalit_file(self):
86+
def test_invalid_file(self):
8787
geo_elevation_data = mod_srtm.get_data()
8888
geo_file = geo_elevation_data.get_file(-47.0, -13.99)
8989
self.assertEquals(None, geo_file)
@@ -97,3 +97,34 @@ def test_coordinates_in_file(self):
9797
self.assertEquals(geo_file.get_elevation(47, 13),
9898
geo_file.get_elevation(47, 13))
9999

100+
def test_without_approximation(self):
101+
geo_elevation_data = mod_srtm.get_data()
102+
103+
self.assertEquals(geo_elevation_data.get_elevation(47.1, 13.1, approximate=False),
104+
geo_elevation_data.get_elevation(47.1, 13.1))
105+
106+
# SRTM elevations are always integers:
107+
elevation = geo_elevation_data.get_elevation(47.1, 13.1)
108+
self.assertTrue(int(elevation) == elevation)
109+
110+
def test_with_approximation(self):
111+
geo_elevation_data = mod_srtm.get_data()
112+
113+
self.assertNotEquals(geo_elevation_data.get_elevation(47.1, 13.1, approximate=True),
114+
geo_elevation_data.get_elevation(47.1, 13.1))
115+
116+
# When approximating a random point, it probably won't be a integer:
117+
elevation = geo_elevation_data.get_elevation(47.1, 13.1, approximate=True)
118+
self.assertTrue(int(elevation) != elevation)
119+
120+
def test_approximation(self):
121+
# TODO(TK) Better tests for approximation here:
122+
geo_elevation_data = mod_srtm.get_data()
123+
elevation_without_approximation = geo_elevation_data.get_elevation(47, 13)
124+
elevation_with_approximation = geo_elevation_data.get_elevation(47, 13, approximate=True)
125+
126+
print elevation_without_approximation
127+
print elevation_with_approximation
128+
129+
self.assertNotEquals(elevation_with_approximation, elevation_without_approximation)
130+
self.assertTrue(abs(elevation_with_approximation - elevation_without_approximation) < 30)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy