make reverse geocoding nominatim compatible (#7349)

* convert input WGS84 coords to Lambert93
 * nominatim like url schema and output

Tests for streets prefixes and splitting
This commit is contained in:
Serghei Mihai 2015-06-04 17:25:16 +02:00
parent 986135e8bf
commit 9c51b590dd
6 changed files with 155 additions and 47 deletions

2
debian/control vendored
View File

@ -9,7 +9,7 @@ Standards-Version: 3.9.1
Package: python-passerelle-montpellier-sig
Architecture: all
Depends: ${misc:Depends}, ${python:Depends}
Depends: ${misc:Depends}, ${python:Depends}, python-pyproj
Description: Passerelle extension for Montpellier's GIS

View File

@ -41,7 +41,7 @@ Service URL : {{ object.service_url }}
<a href="{% url 'montpellier-sig-voiecommune' slug=object.slug nom_rue='montp' %}">{{ site_base_uri }}{% url 'montpellier-sig-view' slug=object.slug %}voiecommune/<i>&lt;montp&gt;</i></a>
</li>
<li>{% trans 'Get address by geographical position:' %}
<a href="{% url 'montpellier-sig-adresse' slug=object.slug lat='771933.239730606' long='6279155.419609674' %}">{{ site_base_uri }}{% url 'montpellier-sig-adresse' slug=object.slug lat='771933.239730606' long='6279155.419609674' %}</a>
<a href="{% url 'montpellier-sig-adresse' slug=object.slug %}?lat=52.5487429714954&lon=-1.81602098644987">{{ site_base_uri }}{% url 'montpellier-sig-adresse' slug=object.slug %}?lat=52.5487429714954&lon=-1.81602098644987</a>
</li>
</ul>

View File

@ -0,0 +1,72 @@
import json
from django.test import TestCase
from django.test.client import Client
from django.core.urlresolvers import reverse
from passerelle_montpellier_sig.models import MontpellierSig
from passerelle_montpellier_sig.views import prefix_cleanup, split_street
class PrefixCleanupTestCase(TestCase):
def test_prefix_alle(self):
self.assertEqual(prefix_cleanup('ALL DE LA PAIX'), 'ALLEE DE LA PAIX')
def test_prefix_viaduc(self):
self.assertEqual(prefix_cleanup('VIAD ALPHONSE LOUBAT'), 'VIADUC ALPHONSE LOUBAT')
def test_prefix_voie(self):
self.assertEqual(prefix_cleanup('VOI DOMITIENNE'), 'VOIE DOMITIENNE')
def test_prefix_square(self):
self.assertEqual(prefix_cleanup('SQ SAINT FIACRE'), 'SQUARE SAINT FIACRE')
def test_prefix_terasse(self):
self.assertEqual(prefix_cleanup('TSSE TERRASSE DES ALLEES DU BOIS'), 'TERRASSE DES ALLEES DU BOIS')
def test_prefix_route(self):
self.assertEqual(prefix_cleanup('RTE DE LODEVE'), 'ROUTE DE LODEVE')
def test_prefix_rondpoint(self):
self.assertEqual(prefix_cleanup('RPT RENE CHAR'), 'ROND-POINT RENE CHAR')
def test_prefix_rue(self):
self.assertEqual(prefix_cleanup('R WILLIAM ET CATHERINE BOOTH'), 'RUE WILLIAM ET CATHERINE BOOTH')
def test_prefix_place(self):
self.assertEqual(prefix_cleanup('PL PABLO PICASSO'), 'PLACE PABLO PICASSO')
def test_prefix_passage(self):
self.assertEqual(prefix_cleanup('PAS HANS CHRISTIAN ANDERSEN'), 'PASSAGE HANS CHRISTIAN ANDERSEN')
def test_prefix_jardin(self):
self.assertEqual(prefix_cleanup('JARD LES JARDINS DU CORUM'), 'JARDIN LES JARDINS DU CORUM')
def test_prefix_impasse(self):
self.assertEqual(prefix_cleanup('IMP VILLEHARDOUIN'), 'IMPASSE VILLEHARDOUIN')
def test_prefix_esplanade(self):
self.assertEqual(prefix_cleanup('ESP DE LA MUSIQUE'), 'ESPLANADE DE LA MUSIQUE')
def test_prefix_chausse(self):
self.assertEqual(prefix_cleanup('CHE DES GRENADIERS'), 'CHAUSSEE DES GRENADIERS')
def test_prefix_boulevard(self):
self.assertEqual(prefix_cleanup('BD RENOUVIER'), 'BOULEVARD RENOUVIER')
def test_prefix_avenue(self):
self.assertEqual(prefix_cleanup('AV RAYMOND DUGRAND'), 'AVENUE RAYMOND DUGRAND')
class ReverseGeolocTest(TestCase):
def test_get_rue(self):
self.assertEqual(split_street('17 bis R WILLIAM ET CATHERINE BOOTH'), ('17 bis', 'RUE WILLIAM ET CATHERINE BOOTH'))
def test_split_impasse(self):
self.assertEqual(split_street(' 5 IMP VILLEHARDOUIN'), ('5', 'IMPASSE VILLEHARDOUIN'))
def test_split_avenue(self):
self.assertEqual(split_street('42 AV RAYMOND DUGRAND '), ('42', 'AVENUE RAYMOND DUGRAND'))

View File

@ -13,7 +13,7 @@ public_urlpatterns = patterns('',
url(r'^(?P<slug>[\w,-]+)/voies/(?P<insee>\d+)$', VoiesView.as_view(), name='montpellier-sig-voies'),
url(r'^(?P<slug>[\w,-]+)/voies/(?P<insee>\d+)/(?P<nom_rue>[\w ]+)/numero$', VoiesCommuneView.as_view(), name='montpellier-voies-commune'),
url(r'^(?P<slug>[\w,-]+)/voiecommune/(?P<nom_rue>[\w ]+)$', VoieCommuneView.as_view(), name='montpellier-sig-voiecommune'),
url(r'^(?P<slug>[\w,-]+)/adresse/(?P<lat>[^/]+)/(?P<long>[^/]+)$', AdresseView.as_view(), name='montpellier-sig-adresse')
url(r'^(?P<slug>[\w,-]+)/reverse$', AdresseView.as_view(), name='montpellier-sig-adresse')
)
management_urlpatterns = patterns('',

View File

@ -1,16 +1,72 @@
import requests
import unicodedata
import pyproj
from django.views.generic.detail import SingleObjectMixin, DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.views.generic.base import View, RedirectView
from django.core.urlresolvers import reverse
from django.http import HttpResponseBadRequest
from passerelle import utils
from .models import MontpellierSig
from .forms import MontpellierSigForm
prefix_map = {
'ALL': 'ALLEE',
'AUTO': 'AUTOROUTE',
'AV': 'AVENUE',
'BASS': 'BASSIN',
'BD': 'BOULEVARD',
'CAR': 'CARREFOUR',
'CHE': 'CHAUSSEE',
'COUR': 'COUR',
'CRS': 'COURS',
'DESC': 'DESCENTE',
'DOM': 'DOMAINE',
'ENCL': 'ENCLOS',
'ESP': 'ESPLANADE',
'ESPA': 'ESPACE',
'GR': '', # "GR GRAND-RUE JEAN MOULIN"
'IMP': 'IMPASSE',
'JARD': 'JARDIN',
'MAIL': '', # "MAIL LE GRAND MAIL"
'PARC': 'PARC',
'PARV': '', # "PARV PARVIS DE LA LEGION D HONNEUR"
'PAS': 'PASSAGE',
'PL': 'PLACE',
'PLAN': 'PLAN',
'PONT': 'PONT',
'QUA': 'QUAI',
'R': 'RUE',
'RAMB': '', # "RAMB RAMBLA DES CALISSONS"
'RPT': 'ROND-POINT',
'RTE': 'ROUTE',
'SQ': 'SQUARE',
'TSSE': '', # "TSSE TERRASSE DES ALLEES DU BOIS"
'TUN': 'TUNNEL',
'VIAD': 'VIADUC',
'VOI': 'VOIE',
}
def prefix_cleanup(name):
name = name.strip()
for prefix, full in prefix_map.items():
if name.startswith(prefix + ' '):
name = (full + name[len(prefix):]).strip()
return name
def split_street(name):
name = name.strip()
for prefix, full in prefix_map.items():
prefix += ' '
if prefix in name:
index, name = name.split(prefix)
index = index.strip()
name = prefix_cleanup(prefix + name)
return index, name
class SigCreateView(CreateView):
model = MontpellierSig
@ -55,51 +111,11 @@ class VoiesView(View, SingleObjectMixin):
def get(self, request, *args, **kwargs):
insee = kwargs['insee']
prefix_map = {
'ALL': 'ALLEE',
'AUTO': 'AUTOROUTE',
'AV': 'AVENUE',
'BASS': 'BASSIN',
'BD': 'BOULEVARD',
'CAR': 'CARREFOUR',
'CHE': 'CHAUSSEE',
'COUR': 'COUR',
'CRS': 'COURS',
'DESC': 'DESCENTE',
'DOM': 'DOMAINE',
'ENCL': 'ENCLOS',
'ESP': 'ESPLANADE',
'ESPA': 'ESPACE',
'GR': '', # "GR GRAND-RUE JEAN MOULIN"
'IMP': 'IMPASSE',
'JARD': 'JARDIN',
'MAIL': '', # "MAIL LE GRAND MAIL"
'PARC': 'PARC',
'PARV': '', # "PARV PARVIS DE LA LEGION D HONNEUR"
'PAS': 'PASSAGE',
'PL': 'PLACE',
'PLAN': 'PLAN',
'PONT': 'PONT',
'QUA': 'QUAI',
'R': 'RUE',
'RAMB': '', # "RAMB RAMBLA DES CALISSONS"
'RPT': 'ROND-POINT',
'RTE': 'ROUTE',
'SQ': 'SQUARE',
'TSSE': '', # "TSSE TERRASSE DES ALLEES DU BOIS"
'TUN': 'TUNNEL',
'VIAD': 'VIADUC',
'VOI': 'VOIE',
}
result = self.get_object().sig_request('commune/' + insee + '/voie')
voies = []
for i in result:
voie = i['attributes']['nom_voie']
for prefix, full in prefix_map.items():
if voie.startswith(prefix + ' '):
voie = (full + voie[len(prefix):]).strip()
voies.append({'id': i['attributes']['nom_voie'],
'text': voie})
voies.append({'id': voie, 'text': prefix_cleanup(voie)})
if 'q' in request.GET and request.GET['q']:
q = request.GET['q'].upper()
@ -152,5 +168,24 @@ class AdresseView(View, SingleObjectMixin):
model = MontpellierSig
def get(self, request, *args, **kwargs):
result = self.get_object().sig_request('adresse/' + kwargs['lat'] + '/' + kwargs['long'])
return utils.response_for_json(request, {'data': result})
lat = request.GET.get('lat')
lon = request.GET.get('lon')
# WGS84: epsg:4326
wgs84 = pyproj.Proj(init='epsg:4326')
# Lambert93: epsg:2154
lambert93 = pyproj.Proj(init='epsg:2154')
try:
l_lat, l_lon = pyproj.transform(wgs84, lambert93, lat, lon)
except TypeError:
return HttpResponseBadRequest()
result = self.get_object().sig_request('adresse/%s/%s' %(l_lat, l_lon))
house_number, road = split_street(result.get('voie'))
address = {'road': road,
'house_number': house_number,
'city': result.get('commune'),
'neighbourhood': result.get('sousquartier'),
'postcode': result.get('codepostal'),
'suburb': result.get('quartier'),
'country': 'France',
}
return utils.response_for_json(request, {'address': address})

View File

@ -94,7 +94,8 @@ setup(
'Programming Language :: Python :: 2',
],
install_requires=['django>=1.7, <1.8',
],
'pyproj'
],
zip_safe=False,
entry_points={
'passerelle.plugin': ['passerelle_montpellier_sig = passerelle_montpellier_sig:Plugin'],