diff --git a/mapit/management/commands/mapit_import_postal_codes.py b/mapit/management/commands/mapit_import_postal_codes.py index f6b62cfe..ae092b1f 100644 --- a/mapit/management/commands/mapit_import_postal_codes.py +++ b/mapit/management/commands/mapit_import_postal_codes.py @@ -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() diff --git a/mapit/models.py b/mapit/models.py index c882c48b..a9173d1e 100644 --- a/mapit/models.py +++ b/mapit/models.py @@ -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) @@ -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())) diff --git a/mapit/templates/mapit/postcode.html b/mapit/templates/mapit/postcode.html index 7369216d..e798aaa4 100644 --- a/mapit/templates/mapit/postcode.html +++ b/mapit/templates/mapit/postcode.html @@ -13,7 +13,7 @@

{{ postcode.postcode }}

E/N: {{ postcode.easting }}, {{ postcode.northing }} {% endif %} {% if postcode.wgs84_lat or postcode.wgs84_lon %} -
  • {% trans "WGS84 lat/lon" %}: {{ postcode.wgs84_lat }}, {{ postcode.wgs84_lon }} +
  • {% trans "WGS84 lat/lon" %}: {{ postcode.wgs84_lat|floatformat:-6 }}, {{ postcode.wgs84_lon|floatformat:-6 }} {% else %}
  • {% blocktrans trimmed %} No location information. Note this is a valid postcode (otherwise you would have got a 404), just one for which we don’t know the location. @@ -36,7 +36,7 @@

    {{ postcode.postcode }}

    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); diff --git a/mapit/tests/test_names.py b/mapit/tests/test_names.py index 146b38ef..9c1d87c8 100644 --- a/mapit/tests/test_names.py +++ b/mapit/tests/test_names.py @@ -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”') diff --git a/mapit/tests/test_views.py b/mapit/tests/test_views.py index 7ea42667..bcb75446 100644 --- a/mapit/tests/test_views.py +++ b/mapit/tests/test_views.py @@ -1,4 +1,5 @@ import json +import unittest from django.test import TestCase from django.conf import settings @@ -6,8 +7,6 @@ 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): @@ -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) @@ -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' diff --git a/mapit_gb/countries.py b/mapit_gb/countries.py index 57669124..c279290b 100644 --- a/mapit_gb/countries.py +++ b/mapit_gb/countries.py @@ -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 diff --git a/mapit_gb/tests.py b/mapit_gb/tests.py index 0f650d36..98007f95 100644 --- a/mapit_gb/tests.py +++ b/mapit_gb/tests.py @@ -1,3 +1,4 @@ +import unittest from django.conf import settings from django.test import TestCase from django.contrib.gis.geos import Polygon, Point @@ -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', @@ -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, @@ -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): @@ -133,7 +143,7 @@ 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, @@ -141,8 +151,8 @@ def test_nearest_json(self): '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]) } }) @@ -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)