Commit 1832e49b authored by Baptiste Jonglez's avatar Baptiste Jonglez

Allow to use several altitude providers

Two altitude providers are now used by default:

- a very accurate provider, but limited to France
- as a fallback, a less accurate provider, but with a global coverage
parent 028abfd9
from __future__ import unicode_literals, division, print_function
import requests
import logging
import re
logger = logging.getLogger(__name__)
class AltitudeProvider(object):
url_template = "{lon}/{lat}"
def parse_answer(self, req):
"""[req] is a Request instances from requests. Should return a float."""
return float(req.text)
except ValueError:
class GeonamesProvider(AltitudeProvider):
url_template = "{lat}&lng={lon}&username=celutz&style=full"
class GeoportailProvider(AltitudeProvider):
url_template = "{lon}&lat={lat}&indent=false&crs=%27CRS:84%27&zonly=true"
def parse_answer(self, req):
m ='<z>(.*)</z>', req.text)
if m == None:
raise ValueError
return float(
# Main function
def get_altitude(providers, timeout, latitude, longitude):
"""Given a list of altitude provider classes, and a timeout for each
provider, try them all in order until we obtain a reasonable altitude
for the given coordinates.
If all providers fail, returns None.
# Try all providers in order
for Provider in providers:
name = Provider.__name__"Trying {}…".format(name))
provider = Provider()
url = provider.url_template.format(lat=latitude, lon=longitude)
r = requests.get(url, timeout=timeout)
except requests.exceptions.ReadTimeout:
logger.warning("{} timeout out after {} seconds".format(name, timeout))
if r.status_code != 200:
alt = provider.parse_answer(r)"Got {}m".format(alt))
if alt < 0:
return alt
except ValueError:
# If all providers failed, return nothing
from django.conf.urls import url
from django.views.decorators.cache import cache_page
from altitude.views import geonames_altitude
from altitude.views import get_altitude
urlpatterns = [
url(r'^(?P<lat>-?\d+(?:\.\d+)?)/(?P<lon>-?\d+(?:\.\d+)?)/$', cache_page(7*24*60*60)(geonames_altitude)),
url(r'^(?P<lat>-?\d+(?:\.\d+)?)/(?P<lon>-?\d+(?:\.\d+)?)/$', cache_page(7*24*60*60)(get_altitude)),
import requests
import logging
from django.http import HttpResponse, HttpResponseServerError
from django.conf import settings
logger = logging.getLogger(__name__)
import altitude.providers
def geonames_altitude(request, lat, lon):
def get_altitude(request, lat, lon):
lat = float(lat)
lon = float(lon)
url = settings.GEONAMES_ASTERGDEM.format(lat=lat, lon=lon)
r = requests.get(url)
if r.status_code != 200:
return HttpResponseServerError()
# The API sometimes returns an error but still sends a 200 code,
# so we validate the answer just to make sure...
return HttpResponse(float(r.text))
except ValueError:
logger.warning(" error: {}".format(r.text))
alt = altitude.providers.get_altitude(settings.ALTITUDE_PROVIDERS,
lat, lon)
if alt == None:
return HttpResponseServerError()
return HttpResponse(alt)
......@@ -12,6 +12,7 @@
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
import altitude.providers
# Quick-start development settings - unsuitable for production
# See
......@@ -119,8 +120,11 @@ STATIC_URL = '/static/'
# Is it required to login to use celutz?
GEONAMES_ASTERGDEM = "{lat}&lng={lon}&username=celutz&style=full"
# Altitude providers are tried in order until obtaining a result.
ALTITUDE_PROVIDERS = [altitude.providers.GeoportailProvider,
# Connection timeout for each provider, in seconds
# For uploaded panorama
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment