Skip to content

Commit

Permalink
[UK] Use database for co-ordinate transformation.
Browse files Browse the repository at this point in the history
If the application is running on a server with GDAL 1.9 (and maybe 1.8),
its OSGB co-ordinate transformation can be up to a few metres out. As we
use the transformation by the database when saving new coordinates, also
use it when fetching so we can match and display accurate information.

https://trac.osgeo.org/gdal/ticket/4597 is the GDAL ticket that explains
that it is fixed in GDAL 1.10.
  • Loading branch information
dracos committed May 9, 2017
1 parent 6be8671 commit 212d387
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 33 deletions.
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()))
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
24 changes: 15 additions & 9 deletions mapit_gb/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,27 @@ def setUp(self):
code='E05000025',
)

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 +119,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 +139,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 Down

0 comments on commit 212d387

Please sign in to comment.