Peter Landgren: 02659 support for RT90 in PlaceUtils.py
svn: r11778
This commit is contained in:
parent
79b25acf9c
commit
31ac581c3a
@ -30,6 +30,7 @@
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gettext import gettext as _
|
||||
import math
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@ -285,6 +286,8 @@ def conv_lat_lon(latitude, longitude, format="D.D4"):
|
||||
i.e. ±DDMM.MMM±DDDMM.MMM
|
||||
'ISO-DMS' : ISO 6709 degree, minutes, seconds notation
|
||||
i.e. ±DDMMSS.SS±DDDMMSS.SS
|
||||
'RT90' : Output format for the Swedish coordinate system RT90
|
||||
|
||||
Return value: a tuple of 2 strings, or a string (for ISO formats)
|
||||
If conversion fails: returns: (None, None) or None (for ISO formats)
|
||||
Some generalities:
|
||||
@ -292,7 +295,7 @@ def conv_lat_lon(latitude, longitude, format="D.D4"):
|
||||
-180 <= longitude < +180 with +000 prime meridian
|
||||
and -180 180th meridian
|
||||
"""
|
||||
|
||||
|
||||
# we start the function changing latitude/longitude in english
|
||||
if latitude.find('N') == -1 and latitude.find('S') == -1:
|
||||
# entry is not in english, convert to english
|
||||
@ -337,12 +340,16 @@ def conv_lat_lon(latitude, longitude, format="D.D4"):
|
||||
str_lon ="-180.0000"
|
||||
return ("%.4f" % lat_float , str_lon)
|
||||
|
||||
if format == "D.D8":
|
||||
if format == "D.D8" or format == "RT90":
|
||||
# correct possible roundoff error
|
||||
str_lon = "%.8f" % (lon_float)
|
||||
if str_lon == "180.00000000":
|
||||
str_lon ="-180.00000000"
|
||||
return ("%.8f" % lat_float , str_lon)
|
||||
if format == "RT90":
|
||||
tx = __conv_WGS84_SWED_RT90(lat_float, lon_float)
|
||||
return ("%i" % tx[0], "%i" % tx[1])
|
||||
else:
|
||||
return ("%.8f" % lat_float , str_lon)
|
||||
|
||||
|
||||
deg_lat = int(lat_float)
|
||||
@ -481,6 +488,112 @@ def conv_lat_lon(latitude, longitude, format="D.D4"):
|
||||
|
||||
|
||||
|
||||
def atanh(x):
|
||||
"""arctangent hyperbolicus"""
|
||||
return 1.0/2.0*math.log((1.0 + x)/(1.0 -x))
|
||||
|
||||
|
||||
def __conv_WGS84_SWED_RT90(lat, lon):
|
||||
"""
|
||||
Input is lat and lon as two float numbers
|
||||
Output is X and Y coordinates in RT90
|
||||
as a tuple of float numbers
|
||||
|
||||
The code below converts to/from the Swedish RT90 koordinate
|
||||
system. The converion functions use "Gauss Conformal Projection
|
||||
(Transverse Marcator)" Krüger Formulas.
|
||||
The constanst are for the Swedish RT90-system.
|
||||
With other constants the conversion should be useful for
|
||||
other geographical areas.
|
||||
|
||||
"""
|
||||
# Some constants used for conversion to/from Swedish RT90
|
||||
f = 1.0/298.257222101
|
||||
e2 = f*(2.0-f)
|
||||
n = f/(2.0-f)
|
||||
L0 = math.radians(15.8062845294) # 15 deg 48 min 22.624306 sec
|
||||
k0 = 1.00000561024
|
||||
a = 6378137.0 # meter
|
||||
at = a/(1.0+n)*(1.0+ 1.0/4.0* pow(n,2)+1.0/64.0*pow(n,4))
|
||||
FN = -667.711 # m
|
||||
FE = 1500064.274 # m
|
||||
|
||||
#the conversion
|
||||
lat_rad = math.radians(lat)
|
||||
lon_rad = math.radians(lon)
|
||||
A = e2
|
||||
B = 1.0/6.0*(5.0*pow(e2,2) - pow(e2,3))
|
||||
C = 1.0/120.0*(104.0*pow(e2,3) - 45.0*pow(e2,4))
|
||||
D = 1.0/1260.0*(1237.0*pow(e2,4))
|
||||
DL = lon_rad - L0
|
||||
E = A + B*pow(math.sin(lat_rad),2) + \
|
||||
C*pow(math.sin(lat_rad),4) + \
|
||||
D*pow(math.sin(lat_rad),6)
|
||||
psi = lat_rad - math.sin(lat_rad)*math.cos(lat_rad)*E
|
||||
xi = math.atan2(math.tan(psi),math.cos(DL))
|
||||
eta = atanh(math.cos(psi)*math.sin(DL))
|
||||
B1 = 1.0/2.0*n - 2.0/3.0*pow(n,2) + 5.0/16.0*pow(n,3) + 41.0/180.0*pow(n,4)
|
||||
B2 = 13.0/48.0*pow(n,2) - 3.0/5.0*pow(n,3) + 557.0/1440.0*pow(n,4)
|
||||
B3 = 61.0/240.0*pow(n,3) - 103.0/140.0*pow(n,4)
|
||||
B4 = 49561.0/161280.0*pow(n,4)
|
||||
X = xi + B1*math.sin(2.0*xi)*math.cosh(2.0*eta) + \
|
||||
B2*math.sin(4.0*xi)*math.cosh(4.0*eta) + \
|
||||
B3*math.sin(6.0*xi)*math.cosh(6.0*eta) + \
|
||||
B4*math.sin(8.0*xi)*math.cosh(8.0*eta)
|
||||
Y = eta + B1*math.cos(2.0*xi)*math.sinh(2.0*eta) + \
|
||||
B2*math.cos(4.0*xi)*math.sinh(4.0*eta) + \
|
||||
B3*math.cos(6.0*xi)*math.sinh(6.0*eta) + \
|
||||
B4*math.cos(8.0*xi)*math.sinh(8.0*eta)
|
||||
X = X*k0*at + FN
|
||||
Y = Y*k0*at + FE
|
||||
return (X, Y)
|
||||
|
||||
def __conv_SWED_RT90_WGS84(X, Y):
|
||||
"""
|
||||
Input is X and Y coordinates in RT90 as float
|
||||
Output is lat and long in degrees, float as tuple
|
||||
"""
|
||||
# Some constants used for conversion to/from Swedish RT90
|
||||
f = 1.0/298.257222101
|
||||
e2 = f*(2.0-f)
|
||||
n = f/(2.0-f)
|
||||
L0 = math.radians(15.8062845294) # 15 deg 48 min 22.624306 sec
|
||||
k0 = 1.00000561024
|
||||
a = 6378137.0 # meter
|
||||
at = a/(1.0+n)*(1.0+ 1.0/4.0* pow(n,2)+1.0/64.0*pow(n,4))
|
||||
FN = -667.711 # m
|
||||
FE = 1500064.274 # m
|
||||
|
||||
xi = (X - FN)/(k0*at)
|
||||
eta = (Y - FE)/(k0*at)
|
||||
D1 = 1.0/2.0*n - 2.0/3.0*pow(n,2) + 37.0/96.0*pow(n,3) - 1.0/360.0*pow(n,4)
|
||||
D2 = 1.0/48.0*pow(n,2) + 1.0/15.0*pow(n,3) - 437.0/1440.0*pow(n,4)
|
||||
D3 = 17.0/480.0*pow(n,3) - 37.0/840.0*pow(n,4)
|
||||
D4 = 4397.0/161280.0*pow(n,4)
|
||||
xip = xi - D1*math.sin(2.0*xi)*math.cosh(2.0*eta) - \
|
||||
D2*math.sin(4.0*xi)*math.cosh(4.0*eta) - \
|
||||
D3*math.sin(6.0*xi)*math.cosh(6.0*eta) - \
|
||||
D4*math.sin(8.0*xi)*math.cosh(8.0*eta)
|
||||
etap = eta - D1*math.cos(2.0*xi)*math.sinh(2.0*eta) - \
|
||||
D2*math.cos(4.0*xi)*math.sinh(4.0*eta) - \
|
||||
D3*math.cos(6.0*xi)*math.sinh(6.0*eta) - \
|
||||
D4*math.cos(8.0*xi)*math.sinh(8.0*eta)
|
||||
psi = math.asin(math.sin(xip)/math.cosh(etap))
|
||||
DL = math.atan2(math.sinh(etap),math.cos(xip))
|
||||
LON = L0 + DL
|
||||
A = e2 + pow(e2,2) + pow(e2,3) + pow(e2,4)
|
||||
B = -1.0/6.0*(7.0*pow(e2,2) + 17*pow(e2,3) + 30*pow(e2,4))
|
||||
C = 1.0/120.0*(224.0*pow(e2,3) + 889.0*pow(e2,4))
|
||||
D = 1.0/1260.0*(4279.0*pow(e2,4))
|
||||
E = A + B*pow(math.sin(psi),2) + \
|
||||
C*pow(math.sin(psi),4) + \
|
||||
D*pow(math.sin(psi),6)
|
||||
LAT = psi + math.sin(psi)*math.cos(psi)*E
|
||||
LAT = math.degrees(LAT)
|
||||
LON = math.degrees(LON)
|
||||
return LAT, LON
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# For Testing the convert function in this module, apply it as a script:
|
||||
@ -497,6 +610,7 @@ if __name__ == '__main__':
|
||||
format4 = "ISO-D"
|
||||
format5 = "ISO-DM"
|
||||
format6 = "ISO-DMS"
|
||||
format7 = "RT90"
|
||||
print "Testing conv_lat_lon function, "+text+':'
|
||||
res1, res2 = conv_lat_lon(lat1,lon1,format0)
|
||||
print lat1,lon1,"in format",format0, "is ",res1,res2
|
||||
@ -511,13 +625,26 @@ if __name__ == '__main__':
|
||||
res = conv_lat_lon(lat1,lon1,format5)
|
||||
print lat1,lon1,"in format",format5, "is",res
|
||||
res = conv_lat_lon(lat1,lon1,format6)
|
||||
print lat1,lon1,"in format",format6, "is",res,"\n"
|
||||
print lat1,lon1,"in format",format6, "is",res
|
||||
res1, res2 = conv_lat_lon(lat1,lon1,format7)
|
||||
print lat1,lon1,"in format",format7, "is",res1,res2,"\n"
|
||||
|
||||
def test_formats_fail(lat1,lon1,text=''):
|
||||
print "This test should make conv_lat_lon function fail, "+text+":"
|
||||
res1, res2 = conv_lat_lon(lat1,lon1)
|
||||
print lat1,lon1," fails to convert, result=", res1,res2,"\n"
|
||||
|
||||
def test_RT90_conversion():
|
||||
"""
|
||||
a given lat/lon is converted to RT90 and back as a test:
|
||||
"""
|
||||
la = 59.0 + 40.0/60. + 9.09/3600.0
|
||||
lo = 12.0 + 58.0/60.0 + 57.74/3600.0
|
||||
x, y = __conv_WGS84_SWED_RT90(la, lo)
|
||||
lanew, lonew = __conv_SWED_RT90_WGS84(x,y)
|
||||
assert math.fabs(lanew - la) < 1e-6, math.fabs(lanew - la)
|
||||
assert math.fabs(lonew - lo) < 1e-6, math.fabs(lonew - lo)
|
||||
|
||||
lat, lon = '50.849888888888', '2.885897222222'
|
||||
test_formats_success(lat,lon)
|
||||
lat, lon = u' 50°50\'59.60"N', u' 2°53\'9.23"E'
|
||||
@ -636,3 +763,4 @@ if __name__ == '__main__':
|
||||
lat, lon = u'S 50º52\'21.92"', u'W 124º52\'21.92"'
|
||||
test_formats_success(lat,lon, 'New format with S/W first and another º - character')
|
||||
|
||||
test_RT90_conversion()
|
||||
|
Loading…
x
Reference in New Issue
Block a user