normalize geographic coordinates into -90..90/-180..180 (#20364)

This commit is contained in:
Benjamin Dauvergne 2017-12-01 16:14:55 +01:00 committed by Thomas NOEL
parent 06ef78bb9e
commit c54766c4e3
5 changed files with 42 additions and 7 deletions

View File

@ -15,7 +15,7 @@ import wcs.api # workaround against circular dependencies :/
from wcs.qommon.form import FileSizeWidget, PicklableUpload
from wcs.qommon.humantime import humanduration2seconds, seconds2humanduration
from wcs.qommon.misc import (simplify, json_loads, parse_isotime, format_time,
date_format, get_as_datetime)
date_format, get_as_datetime, normalize_geolocation)
from wcs.admin.settings import FileTypesDirectory
from wcs.scripts import Script
from wcs.qommon import evalutils
@ -399,3 +399,22 @@ def test_email_plain_and_html_with_attachments(emails):
def test_cache():
cache.set('hello', 'world')
assert cache.get('hello') == 'world'
def test_normalize_geolocation():
assert normalize_geolocation({'lat': 10.0, 'lon': 0.0}) == {'lat': 10.0, 'lon': 0.0}
assert normalize_geolocation({'lat': -10.0, 'lon': 0.0}) == {'lat': -10.0, 'lon': 0.0}
assert normalize_geolocation({'lat': 100.0, 'lon': 0.0}) == {'lat': -80.0, 'lon': 0.0}
assert normalize_geolocation({'lat': -100.0, 'lon': 0.0}) == {'lat': 80.0, 'lon': 0.0}
assert normalize_geolocation({'lat': 180.0, 'lon': 0.0}) == {'lat': 0.0, 'lon': 0.0}
assert normalize_geolocation({'lat': -180.0, 'lon': 0.0}) == {'lat': 0.0, 'lon': 0.0}
assert normalize_geolocation({'lat': 200.0, 'lon': 0.0}) == {'lat': 20.0, 'lon': 0.0}
assert normalize_geolocation({'lat': -200.0, 'lon': 0.0}) == {'lat': -20.0, 'lon': 0.0}
assert normalize_geolocation({'lat': 0.0, 'lon': 10.0}) == {'lat': 0.0, 'lon': 10.0}
assert normalize_geolocation({'lat': 0.0, 'lon': -10.0}) == {'lat': 0.0, 'lon': -10.0}
assert normalize_geolocation({'lat': 0.0, 'lon': 200.0}) == {'lat': 0.0, 'lon': -160.0}
assert normalize_geolocation({'lat': 0.0, 'lon': -200.0}) == {'lat': 0.0, 'lon': 160.0}
assert normalize_geolocation({'lat': 0.0, 'lon': 360.0}) == {'lat': 0.0, 'lon': 0.0}
assert normalize_geolocation({'lat': 0.0, 'lon': -360.0}) == {'lat': 0.0, 'lon': 0.0}
assert normalize_geolocation({'lat': 0.0, 'lon': 400.0}) == {'lat': 0.0, 'lon': 40.0}
assert normalize_geolocation({'lat': 0.0, 'lon': -400.0}) == {'lat': 0.0, 'lon': -40.0}

View File

@ -69,7 +69,7 @@ def geojson_formdatas(formdatas, geoloc_key='base', fields=None):
for formdata in formdatas:
if not formdata.geolocations or not geoloc_key in formdata.geolocations:
continue
coords = formdata.geolocations[geoloc_key]
coords = misc.normalize_geolocation(formdata.geolocations[geoloc_key])
status = formdata.get_status()
try:
status_colour = status.colour

View File

@ -2183,6 +2183,9 @@ class MapWidget(CompositeWidget):
def _parse(self, request):
CompositeWidget._parse(self, request)
self.value = self.get('latlng')
lat, lon = self.value.split(';')
lat_lon = misc.normalize_geolocation({'lat': lat, 'lon': lon})
self.value = '%s;%s' % (lat_lon['lat'], lat_lon['lon'])
class HiddenErrorWidget(HiddenWidget):

View File

@ -559,3 +559,15 @@ def get_thumbnail(fp):
fp.seek(0)
raise ThumbnailError()
return image_thumb_fp.getvalue()
def normalize_geolocation(lat_lon):
'''Fit lat into -90/90 and lon into -180/180'''
def wrap(x, mini, maxi):
diff = maxi - mini
return ((x - mini) % diff + diff) % diff + mini
lat = decimal.Decimal(lat_lon['lat'])
lon = decimal.Decimal(lat_lon['lon'])
lat = wrap(lat, decimal.Decimal('-90.0'), decimal.Decimal('90.0'))
lon = wrap(lon, decimal.Decimal('-180.0'), decimal.Decimal('180.0'))
return {'lat': float(lat), 'lon': float(lon)}

View File

@ -29,7 +29,7 @@ from quixote import get_publisher
from qommon import _
from qommon import get_logger
from qommon.form import RadiobuttonsWidget, ComputedExpressionWidget, CheckboxWidget
from qommon.misc import http_get_page
from qommon.misc import http_get_page, normalize_geolocation
from wcs.workflows import WorkflowStatusItem, register_item_class
class GeolocateWorkflowStatusItem(WorkflowStatusItem):
@ -130,7 +130,7 @@ class GeolocateWorkflowStatusItem(WorkflowStatusItem):
get_logger().info('error finding location')
return
coords = data[0]
return {'lon': float(coords['lon']), 'lat': float(coords['lat'])}
return normalize_geolocation({'lon': coords['lon'], 'lat': coords['lat']})
def geolocate_map_variable(self, formdata):
value = self.compute(self.map_variable)
@ -138,12 +138,13 @@ class GeolocateWorkflowStatusItem(WorkflowStatusItem):
return
try:
lat, lon = map(float, value.split(';'))
lat, lon = value.split(';')
lat_lon = normalize_geolocation({'lon': lon, 'lat': lat})
except Exception, e:
get_logger().error('error geolocating from map variable [%r]', e)
return
return {'lon': lon, 'lat': lat}
return lat_lon
def geolocate_photo_variable(self, formdata):
if Image is None:
@ -192,7 +193,7 @@ class GeolocateWorkflowStatusItem(WorkflowStatusItem):
lat = -lat
if lon_ref == 'W':
lon = -lon
return {'lon': lon, 'lat': lat}
return normalize_geolocation({'lon': lon, 'lat': lat})
return