Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UK] Use database for co-ordinate transformation. #299

Merged
merged 3 commits into from
May 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 4 additions & 9 deletions mapit/management/commands/mapit_import_postal_codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,17 +131,12 @@ def do_postcode(self, location=None, srid=None):
pc = Postcode.objects.get(postcode=self.code)
if location:
if pc.location:
curr_location = (pc.location[0], pc.location[1])
curr_location = pc.location
# Postcode locations are stored as WGS84
if settings.MAPIT_COUNTRY == 'GB':
if pc.postcode[0:2] == 'BT':
curr_location = pc.as_irish_grid()
else:
pc.location.transform(27700) # Postcode locations are stored as WGS84
curr_location = (pc.location[0], pc.location[1])
curr_location = tuple(map(round, curr_location))
curr_location = pc.as_uk_grid()
elif srid != 4326:
pc.location.transform(srid) # Postcode locations are stored as WGS84
curr_location = (pc.location[0], pc.location[1])
curr_location = pc.location.transform(srid, clone=True)
if curr_location[0] != location[0] or curr_location[1] != location[1]:
pc.location = location
pc.save()
Expand Down
17 changes: 11 additions & 6 deletions mapit/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,10 @@ def filter_by_area(self, area):
)


def str2int(s):
return int(round(float(s)))


@python_2_unicode_compatible
class Postcode(models.Model):
postcode = models.CharField(max_length=7, db_index=True, unique=True)
Expand Down Expand Up @@ -449,12 +453,13 @@ def as_dict(self):
countries.augment_postcode(self, result)
return result

# Doing this via self.location.transform(29902) gives incorrect results.
# The database has the right proj4 text, the proj file does not. I think.
def as_irish_grid(self):
# Doing this via self.location.transform(27700/29902) can give incorrect results
# with some versions of GDAL. Via the database produces a correct result.
def as_uk_grid(self):
cursor = connection.cursor()
cursor.execute("SELECT ST_AsText(ST_Transform(ST_GeomFromText('POINT(%f %f)', 4326), 29902))" % (
self.location[0], self.location[1]))
srid = 29902 if self.postcode[0:2] == 'BT' else 27700
cursor.execute("SELECT ST_AsText(ST_Transform(ST_GeomFromText('POINT(%f %f)', 4326), %d))" % (
self.location[0], self.location[1], srid))
row = cursor.fetchone()
m = re.match('POINT\((.*?) (.*)\)', row[0])
return list(map(float, m.groups()))
return list(map(str2int, m.groups()))
4 changes: 2 additions & 2 deletions mapit/templates/mapit/postcode.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ <h2>{{ postcode.postcode }}</h2>
E/N: {{ postcode.easting }}, {{ postcode.northing }}
{% endif %}
{% if postcode.wgs84_lat or postcode.wgs84_lon %}
<li>{% trans "WGS84 lat/lon" %}: <a href="https://tools.wmflabs.org/geohack/geohack.php?params={{ postcode.wgs84_lat|floatformat }};{{ postcode.wgs84_lon }}">{{ postcode.wgs84_lat }}, {{ postcode.wgs84_lon }}</a>
<li>{% trans "WGS84 lat/lon" %}: <a href="https://tools.wmflabs.org/geohack/geohack.php?params={{ postcode.wgs84_lat|floatformat:-6 }};{{ postcode.wgs84_lon|floatformat:-6 }}">{{ postcode.wgs84_lat|floatformat:-6 }}, {{ postcode.wgs84_lon|floatformat:-6 }}</a>
{% else %}
<li>{% blocktrans trimmed %}
No location information. Note this <em>is</em> a valid postcode (otherwise you would have got a 404), just one for which we don&rsquo;t know the location.
Expand All @@ -36,7 +36,7 @@ <h2>{{ postcode.postcode }}</h2>
maxZoom: 18
});

var point = new L.LatLng({{ postcode.wgs84_lat }}, {{ postcode.wgs84_lon }});
var point = new L.LatLng({{ postcode.wgs84_lat|floatformat:-6 }}, {{ postcode.wgs84_lon|floatformat:-6 }});
var marker = new L.Marker(point);
map.addLayer(marker);
map.setView(point, 14);
Expand Down
4 changes: 4 additions & 0 deletions mapit/tests/test_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,18 @@ def setUp(self):
def test_new_name_changes_area_name_in_gb(self):
"""We can't use override_settings, as mapit.countries has been set
based upon MAPIT_COUNTRY already in initial import"""
orig_countries = mapit.models.countries
mapit.models.countries = mapit_gb.countries
Name.objects.create(name='New Name (B)', type=self.name_type, area=self.area)
self.assertEqual(self.area.name, 'New Name Borough')
mapit.models.countries = orig_countries

def test_new_name_does_not_change_area_name_elsewhere(self):
orig_countries = mapit.models.countries
mapit.models.countries = None
Name.objects.create(name='New Name', type=self.name_type, area=self.area)
self.assertEqual(self.area.name, 'Big Area')
mapit.models.countries = orig_countries

def test_geometry_name_works(self):
name = smart_text('Big “Area”')
Expand Down
7 changes: 3 additions & 4 deletions mapit/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import json
import unittest

from django.test import TestCase
from django.conf import settings
from django.contrib.gis.geos import Polygon, Point

from mapit.models import Type, Area, Geometry, Generation, Postcode
from mapit.tests.utils import get_content
import mapit_gb.countries
import mapit.views


class AreaViewsTest(TestCase):
Expand Down Expand Up @@ -89,8 +88,8 @@ def test_front_page(self):
response = self.client.get('/')
self.assertContains(response, 'MapIt')

@unittest.skipUnless(settings.MAPIT_COUNTRY == 'GB', 'UK only test')
def test_postcode_submission(self):
mapit.views.countries = mapit_gb.countries
response = self.client.post('/postcode/', {'pc': 'PO14 1NT'}, follow=True)
self.assertRedirects(response, '/postcode/PO141NT.html')
response = self.client.post('/postcode/', {'pc': 'PO141NT.'}, follow=True)
Expand All @@ -107,7 +106,7 @@ def test_example_postcode(self):
url = '/area/%d/example_postcode' % id
response = self.client.get(url)
content = get_content(response)
self.assertEqual(content, self.postcode.postcode)
self.assertEqual(content, str(self.postcode))

def test_nearest_with_bad_srid(self):
url = '/nearest/84/0,0.json'
Expand Down
13 changes: 4 additions & 9 deletions mapit_gb/countries.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,10 @@ def augment_postcode(postcode, result):
pc = postcode.postcode
if is_special_postcode(pc):
return
if pc[0:2] == 'BT':
loc = postcode.as_irish_grid()
result['coordsyst'] = 'I'
else:
loc = postcode.location
loc.transform(27700)
result['coordsyst'] = 'G'
result['easting'] = int(round(loc[0]))
result['northing'] = int(round(loc[1]))
loc = postcode.as_uk_grid()
result['coordsyst'] = 'I' if pc[0:2] == 'BT' else 'G'
result['easting'] = loc[0]
result['northing'] = loc[1]


# Hacky function to restrict certain geographical links in the HTML pages to
Expand Down
33 changes: 22 additions & 11 deletions mapit_gb/tests.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import unittest
from django.conf import settings
from django.test import TestCase
from django.contrib.gis.geos import Polygon, Point
Expand All @@ -16,8 +17,8 @@ def url_postcode(pc):
class GBViewsTest(TestCase):
def setUp(self):
# Make sure we're using the GB postcode functions here
models.countries = countries
utils.countries = countries
self.orig_countries = models.countries
models.countries = utils.countries = countries

self.postcode = models.Postcode.objects.create(
postcode='SW1A1AA',
Expand Down Expand Up @@ -67,21 +68,30 @@ def setUp(self):
code='E05000025',
)

def tearDown(self):
models.countries = utils.countries = self.orig_countries

def test_ni_postcode(self):
postcode = models.Postcode(postcode='BT170XD', location=Point(-6.037555, 54.556533))
grid = postcode.as_uk_grid()
self.assertEqual(grid, [327011, 369351])

def test_postcode_json(self):
pc = self.postcode.postcode
url = '/postcode/%s' % urllib.parse.quote(pc)
response = self.client.get(url)
content = get_content(response)

in_gb_coords = self.postcode.location.transform(27700, clone=True)
in_gb_coords = self.postcode.as_uk_grid()
self.assertEqual(in_gb_coords, [529090, 179645])
pc = countries.get_postcode_display(self.postcode.postcode)
self.assertDictEqual(content, {
'postcode': pc,
'wgs84_lat': self.postcode.location.y,
'wgs84_lon': self.postcode.location.x,
'coordsyst': 'G',
'easting': round(in_gb_coords.x),
'northing': round(in_gb_coords.y),
'easting': round(in_gb_coords[0]),
'northing': round(in_gb_coords[1]),
'areas': {
str(self.area.id): {
'id': self.area.id,
Expand Down Expand Up @@ -113,14 +123,14 @@ def test_partial_json(self):
response = self.client.get(url)
content = get_content(response)
countries.get_postcode_display(self.postcode.postcode)
in_gb_coords = self.postcode.location.transform(27700, clone=True)
in_gb_coords = self.postcode.as_uk_grid()
self.assertDictEqual(content, {
'wgs84_lat': self.postcode.location.y,
'wgs84_lon': self.postcode.location.x,
'coordsyst': 'G',
'postcode': 'SW1A',
'easting': round(in_gb_coords.x),
'northing': round(in_gb_coords.y)
'easting': round(in_gb_coords[0]),
'northing': round(in_gb_coords[1])
})

def test_partial_json_link(self):
Expand All @@ -133,16 +143,16 @@ def test_nearest_json(self):
response = self.client.get(url)
content = get_content(response)
pc = countries.get_postcode_display(self.postcode.postcode)
in_gb_coords = self.postcode.location.transform(27700, clone=True)
in_gb_coords = self.postcode.as_uk_grid()
self.assertDictEqual(content, {
'postcode': {
'distance': 0,
'wgs84_lat': self.postcode.location.y,
'wgs84_lon': self.postcode.location.x,
'coordsyst': 'G',
'postcode': pc,
'easting': round(in_gb_coords.x),
'northing': round(in_gb_coords.y)
'easting': round(in_gb_coords[0]),
'northing': round(in_gb_coords[1])
}
})

Expand All @@ -152,6 +162,7 @@ def test_nearest_json_link(self):
pc = self.postcode.postcode
self.assertContains(response, '"/postcode/%s"' % url_postcode(pc))

@unittest.skipUnless(settings.MAPIT_COUNTRY == 'GB', 'UK only tests')
def test_gss_code(self):
response = self.client.get('/area/E05000025')
self.assertRedirects(response, '/area/%d' % self.area.id)
Expand Down