Content deleted Content added
make composite wrapper function |
factor out data |
||
(50 intermediate revisions by the same user not shown) | |||
Line 45:
local abs = math.abs
local floor = math.floor
local ceil = math.ceil
local sin = math.sin
local cos = math.cos
Line 51 ⟶ 52:
local deg2rad = math.rad
local rad2deg = math.deg
--[[ DATUM SHIFT USING HELMERT TRANSFORMATION
*
* height above the ellipsoid is ignored
* latitude and longitude must be given in decimal degrees
*
* no transformation if abs(latitude)>89 or abs(longitude)>89
* (lifting this restriction requires some more lines of code)
*
* Written in 2009 by user Telford at de.wikipedia
* Based on math described in "A Guide to Coordinate Systems in Great Britain"
* by the UK Ordnance Survey
* URL: https://www.ordnancesurvey.co.uk/documents/resources/guide-coordinate-systems-great-britain.pdf
]]
-- Datum parameters
local data = mw.loadData('Module:Ordnance Survey coordinates/data')
local OSGBglobe = data.OSGBglobe
local IEglobe = data.IEglobe
local WGSglobe = data.WGSglobe
local WGS2OSGBparam = data.WGS2OSGBparam
local OSGB2WGSparam = data.OSGB2WGSparam
local IE2WGSparam = data.IE2WGSparam
local function HelmertDatumShift ( latitude , longitude, param )
-- latitude and longitude are in degrees
-- return if latitude or longitude out of range
if abs(latitude) > 89. or abs(longitude) > 89. then
return {lat=latitude, lon=longitude}
end
param = param or WGS2OSGBparam
-- parameters for ellipsoids
-- Annex A.1, Ordnance Survey document --
local a1 = param.semimajor_src
local b1 = param.semiminor_src
local e1 = param.ecc_src
local a2 = param.semimajor_dst
local b2 = param.semiminor_dst
local e2 = param.ecc_dst
-- convert latitude and longitude to cartesian coordinates
-- math in Annex B.1, Ordnance Survey document
local phi = deg2rad ( latitude )
local lambda = deg2rad ( longitude )
local cosphi = cos ( phi )
local sinphi = sin ( phi )
local coslambda = cos ( lambda )
local sinlambda = sin ( lambda )
local ny = a1 / sqrt ( 1. - e1*sinphi*sinphi )
local x1 = ny * cosphi * coslambda
local y1 = ny * cosphi * sinlambda
local z1 = ny * ( 1. - e1 ) * sinphi
-- the helmert transformation proper
-- Equation 3, Section 6.2, Ordnance Survey document
local x2 = x1 + param.tx + ( param.s0 * x1 - param.rz * y1 + param.ry * z1 )
local y2 = y1 + param.ty + ( param.rz * x1 + param.s0 * y1 - param.rx * z1 )
local z2 = z1 + param.tz + ( -param.ry *x1 + param.rx * y1 + param.s0 * z1 )
-- convert cartesian coordinates to latitude and longitude
-- math in Annex B.2, of Ordnance Survey document
lambda = atan ( y2 / x2 )
local p2 = sqrt ( x2*x2 + y2*y2 )
phi = atan ( z2 / p2*(1.-e2) )
local n0 = 101
local phi_alt
repeat
phi_alt = phi
ny = a2 / sqrt ( 1. - e2 * sin(phi) * sin(phi) )
phi = atan ( (z2 + e2 * ny * sin(phi)) / p2 )
n0 = n0 - 1
until abs ( phi - phi_alt ) <= 0.000000000001 or n0 <= 0
return {lat=rad2deg(phi),lon=rad2deg(lambda)}
end
-- LAT LONG TO OS GRID LIBRARY RESUMES HERE
local function northeast(lett,num,shift)
Line 96 ⟶ 179:
end
local function
local a = datum.semimajor*datum.scale
local
local lat0rad = deg2rad(datum.lat0)
local
local n12 = n1*n1
local
local k=(n-datum.n0)/a+lat0rad
local nextcounter=0
local j3, j4, j5, j6, m
repeat
nextcounter=nextcounter+1
local k3=k-
local k4=k+
j3=(1.0+
j4=(3.0*
j5=(1.875*
j6=35.0/24.0*
m=
k=k+(n-
until abs(n-
local
local
local r=v*(1.0-datum.ecc)/x
local h2=v/r-1.0
local y1=e-
local tank2 = tank*tank
local tank4 = tank2*tank2
local tank6 = tank2*tank4
local yv = y1/v -- dimensionless quantity in series expansion
local yv2 = yv*yv
local
local yv5 = yv3*yv2
local yv7 = yv5*yv2
j3=tank/(2.0*r)
j4=tank/(24.0*r)*(5.0+3.0*tank2+h2-9.0*tank2*h2)
j5=tank/(720.0*r)*(61.0+90.0*tank2+45.0*tank4)
local
local j7=1.0/(cosk*6.0)*(v/r+2.0*tank2)
local
local
j9=j9*(61.0+662.0*tank2+1320.0*tank4+720.0*tank6)
local long=datum.lon0+rad2deg(yv*j6-yv3*j7+yv5*j8-yv7*j9)
local lat=rad2deg(k9)
return {lat=lat,lon=long}
end
local function GBEN2LL(e,n)
local
local helmert = HelmertDatumShift ( latlong.lat, latlong.lon, OSGB2WGSparam)
return {region="GB",lat=helmert.lat,long=helmert.lon}
end
Line 194 ⟶ 253:
local function IrishEN2LL(e,n)
local latlong = EN2LL(e,n,IEglobe)
local helmert = HelmertDatumShift ( latlong.lat, latlong.lon, IE2WGSparam)
return {region="IE",lat=helmert.lat,long=helmert.lon}
end
Line 296 ⟶ 280:
local function NGR2LL(ngr)
local result = {}
local _ = 0
ngr, _ = mw.ustring.gsub(mw.ustring.upper(ngr),"[%s%p]","")
local first, last, lett, num = mw.ustring.find(ngr,"^([A-Z]+)(%d+)$")
Line 318 ⟶ 303:
local function trim(s)
local _ = 0
s, _ = mw.ustring.gsub(s,"^%s+","")
s, _ = mw.ustring.gsub(s,"%s+$","")
Line 339 ⟶ 325:
end
-- generate URL of geohack map
local function geohack(main_args, other_args, LL)
-- create geohack link. Example:
-- https://geohack.toolforge.org/geohack.php?pagename=Mount_Whitney¶ms=36.578580925_N_118.29199495_W_type:mountain_region:US-CA_scale:100000_source:NGS
local url = 'https://geohack.toolforge.org/geohack.php?'
local input = main_args[1]
local namearg = main_args["name"]
local current_page = mw.title.getCurrentTitle()
local pagename = mw.uri.encode( current_page.prefixedText, 'WIKI' )
if not empty(pagename) then
url = url..'pagename='..pagename..'&'
end
url = url..'params='..mw.ustring.format('%.6f',LL.lat)..'_N_'
if LL.long < 0 then
url = url..mw.ustring.format('%.6f',-LL.long)..'_W'
else
url = url..mw.ustring.format('%.6f',LL.long)..'_E'
end
for _, a in ipairs(other_args) do
url = url..'_'..a
end
if not mw.ustring.find(input,"region") and LL.region then
url = url..'_region:'..LL.region
end
if not mw.ustring.find(input,"scale") and
not mw.ustring.find(input,"type") and
not mw.ustring.find(input,"dim") and LL.prec then
url = url..'_dim:'..floor(50*LL.prec+0.5)..'m'
end
if not empty(namearg) then
url = url .. "&title=" .. mw.uri.encode(namearg)
end
return url
end
-- function to generate direct link to OS map
local function directLink(main_args, other_args, LL)
-- create link to Bing server for OS maps. Example:
-- https://www.bing.com/maps/?mkt=en-gb&v=2&cp=56.796026%7E-5.01307&lvl=16.0&sp=Point.56.796029_-5.004711_Ben+Nevis&sty=s&style=s
local current_page = mw.title.getCurrentTitle()
local namearg = mw.uri.encode( main_args["name"] or current_page.prefixedText, 'QUERY' )
local args = {}
for _, a in ipairs(other_args) do
local splitOut = mw.text.split(a, ':', true)
args[splitOut[1]] = splitOut[2]
end
if not args.scale and not args.type and not args.dim then
args.dim = LL.prec and tostring(floor(50*LL.prec+0.5))..'m'
end
args.viewport_cm = 10
local zoom = require('Module:Infobox dim')._zoom
local lvl = zoom(args) or 12
local url = mw.ustring.format('https://www.bing.com/maps/?mkt=en-gb&v=2&cp=%.6f~%.6f&lvl=%d&sp=Point.%.6f_%.6f',LL.lat,LL.long,lvl,LL.lat,LL.long)
if not empty(namearg) then
url = url..'_'..namearg
end
url = url..'&sty=s&style=s'
return url
end
function oscoord._main(main_args)
local input = main_args[1]
if empty(input) then
return warning(nil)
end
local linktitle =
local
local
local args = split(input,'_')
local LL
local restargs = 1
if #args >= 2 and alldigits(args[2]) then
if mw.ustring.sub(args[1],1,1) == 'i' then
Line 379 ⟶ 423:
if not empty(LL.err) then
return linktitle ..warning(LL.err)
end
LL.lat = LL.lat or 0
LL.long = LL.long or 0
local other_args = {}
for i = restargs, #args do
table.insert(other_args, args[i])
end
local url
if not direct then
url = geohack(main_args, other_args, LL)
else
url = directLink(main_args, other_args, LL)
end
if not rawurl then
url = '['..url..' '..linktitle..']'
end
return url
Line 469 ⟶ 496:
]]
local function find_M ( lat_rad )
local e =
local e2 = e*e
local e3 = e*e*e
return
- 5 *
) * lat_rad
- ( 3 * e/8 + 3 *
+ 45 *
) * sin(2 * lat_rad)
+ ( 15 *
45 *
) * sin(4 * lat_rad)
- ( 35 *
) * sin(6 * lat_rad) )
end
Line 595 ⟶ 530:
local lat_rad = deg2rad( latitude )
local e =
local e_prime_sq = e / (1-e)
local v =
local
local T = tank*tank
local T2 = T*T
local C = e_prime_sq * pow( cos(lat_rad), 2)
local A = deg2rad( longitude2 -
local A2 = A*A
local A3 = A2*A
local A4 = A2*A2
local A5 = A3*A2
local A6 = A3*A3
local M = find_M( lat_rad )
local M0 = 0.0
if latitude_origin ~= 0 then
M0 = find_M(deg2rad(
end
local northing =
( (M - M0) + v*tan(lat_rad) *
(
+ (5 - T + 9*C + 4*C*C) *
+ (61 - 58*T +
+ 600*C - 330*e_prime_sq) *
local easting =
( A
+ (1-T+C)*
+ (5 - 18*T +
- 58 * e_prime_sq)*
return {northing=northing,easting=easting}
Line 628 ⟶ 570:
* OSBG36 Easting and Northing
]]
local function LatLon2OSGB36( latlon, prec )
local tm = LatLonOrigin2TM(latlon.lat, latlon.lon)
if not tm then return '' end
if not tonumber(prec) then prec = 5 end
prec = floor(prec+0.5)
if prec > 5 then prec = 5 end
if prec < 1 then prec = 1 end
-- fix by Roger W Haworth
Line 645 ⟶ 591:
local c2 = mw.ustring.sub(letters,indx2,indx2)
local
local
local grid = pow(10.0,5.0-prec)
easting = floor(easting/grid)
northing = floor(northing/grid)
local fmt = '%0'..prec..'d'
local e = mw.ustring.format(fmt, easting)
local n = mw.ustring.format(fmt, northing)
return c1..c2..e..n
Line 652 ⟶ 604:
end
function oscoord._WGS2OSGB(lat,lon,prec)
return LatLon2OSGB36(HelmertDatumShift(lat,lon,WGS2OSGBparam),prec)
end
function oscoord.WGS2OSGB(frame)
local args = getArgs(frame)
return args[1] and args[2] and oscoord._WGS2OSGB(args[1],args[2],args[3]) or ''
end
Line 664 ⟶ 616:
local args = getArgs(frame)
if not args[1] or not args[2] then return '' end
local
if not gridRef or #gridRef == 0 then return '' end
if args[3] then
gridRef = gridRef..'_'..args[3]
end
return oscoord._oscoord({gridRef,args.linktitle,name=args.name})
end
|