વિભાગ:Coordinates: આવૃત્તિઓ વચ્ચેનો તફાવત

Content deleted Content added
improve quick_statement links
→‎try 1: ઢાંચામાં કોર્ડસ બેવડાય છે તે સુધારવા
લીટી ૧:
--[[
This module is intended to replace the functionality of {{Coord}} and related
templates. It provides several methods, including
 
{{#invoke:Coordinates | coord }} : General function formatting and displaying
This module is intended to provide functionality of {{location}} and related
coordinate values.
templates.
 
{{#invoke:Coordinates | dec2dms }} : Simple function for converting decimal
Please do not modify this code without applying the changes first at Module:Coordinates/sandbox and testing
degree values to DMS format.
at Module:Coordinates/sandbox/testcases and Module talk:Coordinates/sandbox/testcases.
 
{{#invoke:Coordinates | dms2dec }} : Simple function for converting DMS format
Authors and maintainers:
to decimal degree format.
* User:Jarekt
* User:Ebraminio
 
{{#invoke:Coordinates | link }} : Export the link used to reach the tools
Functions:
*function p.LocationTemplateCore(frame)
**function p.GeoHack_link(frame)
***function p.lat_lon(frame)
****function p._deg2dms(deg,lang)
***function p.externalLink(frame)
****function p._externalLink(site, globe, latStr, lonStr, lang, attributes)
**function p._getHeading(attributes)
**function p.externalLinksSection(frame)
***function p._externalLink(site, globe, latStr, lonStr, lang, attributes)
*function p.getHeading(frame)
*function p.deg2dms(frame)
 
]]
 
require('Module:No globals')
-- =======================================
-- === Dependencies ======================
-- =======================================
local i18n = require('Module:I18n/coordinates') -- get localized translations of site names
local yesno = require('Module:Yesno')
 
local math_mod = require("Module:Math")
-- =======================================
local coordinates = {};
-- === Hardwired parameters ==============
-- =======================================
 
local current_page = mw.title.getCurrentTitle()
-- Angles associated with each abriviation of compass point names. See [[:en:Points of the compass]]
local page_name = mw.uri.encode( current_page.prefixedText, 'WIKI' );
local compass_points = {
local coord_link = '//tools.wmflabs.org/geohack/geohack.php?pagename=' .. page_name .. '&params='
N = 0,
NBE = 11.25,
NNE = 22.5,
NEBN = 33.75,
NE = 45,
NEBE = 56.25,
ENE = 67.5,
EBN = 78.75,
E = 90,
EBS = 101.25,
ESE = 112.5,
SEBE = 123.75,
SE = 135,
SEBS = 146.25,
SSE = 157.5,
SBE = 168.75,
S = 180,
SBW = 191.25,
SSW = 202.5,
SWBS = 213.75,
SW = 225,
SWBW = 236.25,
WSW = 247.5,
WBS = 258.75,
W = 270,
WBN = 281.25,
WNW = 292.5,
NWBW = 303.75,
NW = 315,
NWBN = 326.25,
NNW = 337.5,
NBW = 348.75,
}
 
--[[ Helper function, replacement for {{coord/display/title}} ]]
-- files to use for different headings
local function displaytitle(s, notes)
local heading_icon = {
local l = "[[Geographic coordinate system|Coordinates]]: " .. s
[ 1] = 'File:Compass-icon bb N.svg',
local co = '<span id="coordinates">' .. l .. notes .. '</span>';
[ 2] = 'File:Compass-icon bb NbE.svg',
return '<span style="font-size: small;">' .. co .. '</span>';
[ 3] = 'File:Compass-icon bb NNE.svg',
end
[ 4] = 'File:Compass-icon bb NEbN.svg',
[ 5] = 'File:Compass-icon bb NE.svg',
[ 6] = 'File:Compass-icon bb NEbE.svg',
[ 7] = 'File:Compass-icon bb ENE.svg',
[ 8] = 'File:Compass-icon bb EbN.svg',
[ 9] = 'File:Compass-icon bb E.svg',
[10] = 'File:Compass-icon bb EbS.svg',
[11] = 'File:Compass-icon bb ESE.svg',
[12] = 'File:Compass-icon bb SEbE.svg',
[13] = 'File:Compass-icon bb SE.svg',
[14] = 'File:Compass-icon bb SEbS.svg',
[15] = 'File:Compass-icon bb SSE.svg',
[16] = 'File:Compass-icon bb SbE.svg',
[17] = 'File:Compass-icon bb S.svg',
[18] = 'File:Compass-icon bb SbW.svg',
[19] = 'File:Compass-icon bb SSW.svg',
[20] = 'File:Compass-icon bb SWbS.svg',
[21] = 'File:Compass-icon bb SW.svg',
[22] = 'File:Compass-icon bb SWbW.svg',
[23] = 'File:Compass-icon bb WSW.svg',
[24] = 'File:Compass-icon bb WbS.svg',
[25] = 'File:Compass-icon bb W.svg',
[26] = 'File:Compass-icon bb WbN.svg',
[27] = 'File:Compass-icon bb WNW.svg',
[28] = 'File:Compass-icon bb NWbW.svg',
[29] = 'File:Compass-icon bb NW.svg',
[30] = 'File:Compass-icon bb NWbN.svg',
[31] = 'File:Compass-icon bb NNW.svg',
[32] = 'File:Compass-icon bb NbW.svg'
}
 
--[[ Helper function, Replacement for {{coord/display/inline}} ]]
-- URL definitions for different sites. Strings: $lat, $lon, $lang, $attr, $page will be
local function displayinline(s, notes)
-- replaced with latitude, longitude, language code, GeoHack attribution parameters and full-page-name strings.
return s .. notes
local SiteURL = {
end
GeoHack = '//tools.wmflabs.org/geohack/geohack.php?pagename=$page&params=$lat_N_$lon_E_$attr&language=$lang',
GoogleEarth = '//tools.wmflabs.org/geocommons/earth.kml?latdegdec=$lat&londegdec=$lon&scale=10000&commons=1',
Proximityrama = '//tools.wmflabs.org/geocommons/proximityrama?latlon=$lat,$lon',
OpenStreetMap1 = '//tools.wmflabs.org/wiwosm/osm-on-ol/commons-on-osm.php?zoom=16&lat=$lat&lon=$lon',
OpenStreetMap2 = '//tools.wmflabs.org/osm4wiki/cgi-bin/wiki/wiki-osm.pl?project=Commons&article=$page&l=$level',
GoogleMaps = {
Mars = '//www.google.com/mars/#lat=$lat&lon=$lon&zoom=8',
Moon = '//www.google.com/moon/#lat=$lat&lon=$lon&zoom=8',
Earth = '//tools.wmflabs.org/wp-world/googlmaps-proxy.php?page=http://tools.wmflabs.org/kmlexport/%3Fproject%3DCommons%26article%3D$page&l=$level&output=classic'
}
}
 
--[[ Helper function, used in detecting DMS formatting ]]
-- Categories
local CoorCatfunction =dmsTest(first, {second)
if type(first) ~= 'string' or type(second) ~= 'string' then
File = '[[Category:Media with locations]]',
return nil
Gallery = '[[Category:Galleries with coordinates]]',
Category = '[[Category:Categories with coordinates]]',
wikidata0 = '[[Category:Pages with coordinates from Wikidata]]',
wikidata1 = '[[Category:Pages with local coordinates and matching wikidata coordinates]]',
wikidata2 = '[[Category:Pages with local coordinates and similar wikidata coordinates]]',
wikidata3 = '[[Category:Pages with local coordinates and mismatching wikidata coordinates]]',
wikidata4 = '[[Category:Pages with local coordinates and missing wikidata coordinates]]',
wikidata5 = '[[Category:Pages with locations and wikidata code to wrong type of entry]]',
globe = '[[Category:Media with %s locations]]',
default = '[[Category:Media with default locations]]',
attribute = '[[Category:Media with erroneous geolocation attributes]]',
erroneous = '[[Category:Media with erroneous locations]]<span style="color:red;font-weight:bold">Error: Invalid parameters!</span>\n'
}
 
local NoLatLonString = 'latitude, longitude'
 
local function langSwitch(list,lang)
local langList = mw.language.getFallbacksFor(lang)
table.insert(langList,1,lang)
for i,language in ipairs(langList) do
if list[language] then
return list[language]
end
end
local s = (first .. second):upper()
return s:find('^[NS][EW]$') or s:find('^[EW][NS]$')
end
 
 
local function add_maplink(lat, lon, marker, text)
--[[ Wrapper function to grab args, see Module:Arguments for this function's documentation. ]]
local tstr = ''
local function makeInvokeFunc(funcName)
if text then
return function (frame)
tstr = string.format('text="%s" ', text)
local args = require('Module:Arguments').getArgs(frame, {
wrappers = 'Template:Coord'
})
return coordinates[funcName](args, frame)
end
return string.format('<maplink %szoom="13" latitude="%f" longitude="%f" class="no-icon">{'..
' "type": "Feature",'..
' "geometry": { "type":"Point", "coordinates":[%f, %f] },'..
' "properties": { "marker-symbol":"%s", "marker-size": "large", "marker-color": "0050d0" }'..
'}</maplink>', tstr, lat, lon, lon, lat, marker)
end
 
--[[ Helper function, handle optional args. ]]
local function add_maplink2(lat1, lon1, lat2, lon2)
local function optionalArg(arg, supplement)
return string.format('<maplink zoom="13" latitude="%f" longitude="%f" class="no-icon">[{'..
return arg and arg .. supplement or ''
' "type": "Feature",'..
' "geometry": { "type":"Point", "coordinates":[%f, %f] },'..
' "properties": { "marker-symbol":"c", "marker-size": "large", "marker-color": "0050d0", "title": "Location on Wikimedia Commons" }'..
'},{'..
' "type": "Feature",'..
' "geometry": { "type":"Point", "coordinates":[%f, %f] },'..
' "properties": { "marker-symbol":"w", "marker-size": "large", "marker-color": "228b22", "title": "Location on Wikidata" }'..
'}]</maplink>', lat2, lon2, lon1, lat1, lon2, lat2)
end
 
--[[
local function info_box(text)
Formats any error messages generated for display
return string.format('<table class="messagebox plainlinks layouttemplate" style="border-collapse:collapse; border-width:2px; border-style:solid; width:100%%; clear: both; '..
]]
'border-color:#f28500; background:#ffe;direction:ltr; border-left-width: 8px; ">'..
local function errorPrinter(errors)
'<tr>'..
local result = ""
'<td class="mbox-image" style="padding-left:.9em;">'..
for i,v in ipairs(errors) do
' [[File:Commons-emblem-issue.svg|class=noviewer|45px]]</td>'..
local errorHTML = '<strong class="error">Coordinates: ' .. v[2] .. '</strong>'
'<td class="mbox-text" style="">%s</td>'..
result = result .. errorHTML .. "<br />"
'</tr></table>', text)
end
return result
end
 
--[[
local function mergeWithWikidata(q, lat1, lon1)
--Determine wethe arerequired givenCSS wikidataclass q-codeto so look up thedisplay coordinates
 
local dist_str=''
Usually geo-nondefault is hidden by CSS, unless a user has overridden this for himself
-- Wikiata coordinates
default is the mode as specificied by the user when calling the {{coord}} template
if q:match( '^[Qq]%d+$' ) then
mode is the display mode (dec or dms) that we will need to determine the css class for
entity = mw.wikibase.getEntity(q)
]]
local function displayDefault(default, mode)
if default == "" then
default = "dec"
end
if default == mode then
return "geo-default"
else
return "geo-nondefault"
entity = q
end
end
q = entity.id
 
local v, lat2, lon2, precision
--[[
if entity then
specPrinter
local P625 = entity:getBestStatements( 'P625' ) -- coordinate location
 
local P159 = entity:getBestStatements( 'P159' ) -- headquarters location
Output formatter. Takes the structure generated by either parseDec
if P625[1] and P625[1].mainsnak.datavalue.value.latitude then
or parseDMS and formats it for inclusion on Wikipedia.
v = P625[1].mainsnak.datavalue.value
]]
elseif P159[1] and P159[1].qualifiers and P159[1].qualifiers.P625 then
local function specPrinter(args, coordinateSpec)
v = P159[1].qualifiers.P625[1].datavalue.value
local uriComponents = coordinateSpec["param"]
end
if uriComponents == "" then
if v and v.globe == 'http://www.wikidata.org/entity/Q2' then
-- RETURN error, should never be empty or nil
lat2 = v.latitude
return "ERROR param was empty"
lon2 = v.longitude
precision = v.precision or 1e-4
precision = math.floor(precision*111000) -- convert precision from degrees to meters and round
precision = math.max(math.min(precision,111000),5) -- bound precision to a number between 5 meters and 1 degree
end
end
if args["name"] then
uriComponents = uriComponents .. "&title=" .. mw.uri.encode(coordinateSpec["name"])
-- compare coordinates
end
local cat = ''
if not lat1 or not lon1 then -- wikidata coordinates only
local geodmshtml = '<span class="geo-dms" title="Maps, aerial photos, and other data for this location">'
lat1 = lat2
.. '<span class="latitude">' .. coordinateSpec["dms-lat"] .. '</span> '
lon1 = lon2
.. '<span class="longitude">' ..coordinateSpec["dms-long"] .. '</span>'
cat = CoorCat.wikidata0
.. '</span>'
elseif lat1 and lon1 and not lat2 and not lon2 then
cat = string.format('The above coordinates are missing from linked Wikidata item [[d:%s|%s]]. Click <span class=\"plainlinks\" title=\"Click to copy to wikidata\">'..
"[http://tools.wmflabs.org/wikidata-todo/quick_statements.php?list=%s%%09P625%%09@%09.5f/%09.5f%%09S143%%09Q565 here]</span> to copy it",
q, q, q, lat1, lon1)
cat = CoorCat.wikidata4 .. info_box(cat)
elseif lat1 and lon1 and lat2 and lon2 then
-- calculate distance
local dLat = math.rad(lat1-lat2)
local dLon = math.rad(lon1-lon2)
local d = math.pow(math.sin(dLat/2),2) + math.pow(math.sin(dLon/2),2) * math.cos(math.rad(lat1)) * math.cos(math.rad(lat2))
d = 2 * math.atan2(math.sqrt(d), math.sqrt(1-d)) -- angular distance in radians
d = 6371000 * d -- radians to meters conversion
d = math.floor(d+0.5) -- rind it to even meters
local frame = mw.getCurrentFrame()
local info = frame:preprocess(add_maplink2(lat1, lon1, lat2, lon2)) -- fancy link to OSM
info = string.format("There is a discrepancy of %i meters between the above coordinates and the ones stored at linked Wikidata item [[d:%s|%s]] (%s, precision: %i m). "..
'Please reconcile them. To copy Commons coordinates to Wikidata, click <span class=\"plainlinks\" title=\"Click to copy to wikidata\">'..
"[http://tools.wmflabs.org/wikidata-todo/quick_statements.php?list=%s%%09P625%%09@%09.5f/%09.5f%%09S143%%09Q565 here]</span>",
d, q, q, info, precision, q, lat1, lon1)
 
local lat = tonumber( coordinateSpec["dec-lat"] ) or 0
if d<20 or d<precision then -- will consider location within 20 meters or precisi0on distance as the same
local geodeclat
cat = CoorCat.wikidata1
if lat < 0 then
dist_str = string.format(' (discrepancy of %i meters between the above coordinates and the ones stored on Wikidata)', d) -- will be displayed when hovering a mouse above wikidata icon
-- FIXME this breaks the pre-existing precision
elseif d>1000 and d>5*precision then -- locations 1 km off and 5 precision distances away are likely wrong
geodeclat = tostring(coordinateSpec["dec-lat"]):sub(2) .. "°S"
cat = CoorCat.wikidata3 .. info_box(info)
else
geodeclat = (coordinateSpec["dec-lat"] or 0) .. "°N"
cat = CoorCat.wikidata2 .. info_box(info)
end
 
local long = tonumber( coordinateSpec["dec-long"] ) or 0
local geodeclong
if long < 0 then
-- FIXME does not handle unicode minus
geodeclong = tostring(coordinateSpec["dec-long"]):sub(2) .. "°W"
else
geodeclong = (coordinateSpec["dec-long"] or 0) .. "°E"
end
local geodechtml = '<span class="geo-dec" title="Maps, aerial photos, and other data for this location">'
-- verify proper P31 (instance of). List is based on https://www.wikidata.org/wiki/Property_talk:P625
.. geodeclat .. ' '
local QCodes = {
.. geodeclong
Q5 = 1, -- human
.. '</span>'
Q11879590 = 1, -- female given name
 
Q202444 = 1, -- given name
local geonumhtml = '<span class="geo">'
Q12308941 = 1, -- male given name
.. coordinateSpec["dec-lat"] .. '; '
Q4167836 = 1, -- Wikimedia category
.. coordinateSpec["dec-long"]
Q4167410 = 1, -- Wikimedia disambiguation page
.. '</span>'
Q783794 = 2, -- company
 
Q4830453 = 2, -- business enterprise
local inner = '<span class="' .. displayDefault(coordinateSpec["default"], "dms" ) .. '">' .. geodmshtml .. '</span>'
}
.. '<span class="geo-multi-punct">&#xfeff; / &#xfeff;</span>'
s = entity:getBestStatements( 'P31' )
.. '<span class="' .. displayDefault(coordinateSpec["default"], "dec" ) .. '">';
if s[1] and s[1].mainsnak.datavalue.value['numeric-id'] then
 
local instanceOf = string.format('Q%i',s[1].mainsnak.datavalue.value['numeric-id'])
if QCodesnot args[instanceOf"name"] then
inner = inner .. geodechtml
cat = '' -- wipe out categories
.. '<span style="display:none">&#xfeff; / ' .. geonumhtml .. '</span></span>'
if QCodes[instanceOf]==1 then -- add problem category
else
cat = CoorCat.wikidata5
inner = inner .. '<span class="vcard">' .. geodechtml
end
.. '<span style="display:none">&#xfeff; / ' .. geonumhtml .. '</span>'
end
.. '<span style="display:none">&#xfeff; (<span class="fn org">'
.. args["name"] .. '</span>)</span></span></span>'
end
 
return '<span class="plainlinks nourlexpansion">' ..
'[' .. coord_link .. uriComponents .. ' ' .. inner .. ']' .. '</span>'
end
 
--[[ Helper function, convert decimal to degrees ]]
local function convert_dec2dms_d(coordinate)
local d = math_mod._round( coordinate, 0 ) .. "°"
return d .. ""
end
 
--[[ Helper function, convert decimal to degrees and minutes ]]
local function convert_dec2dms_dm(coordinate)
coordinate = math_mod._round( coordinate * 60, 0 );
local m = coordinate % 60;
coordinate = math.floor( (coordinate - m) / 60 );
local d = coordinate % 360 .."°"
return lat1,d lon1,.. qstring.format( "%02d′", cat,m dist_str)
end
 
--[[ Helper function, convert decimal to degrees, minutes, and seconds ]]
-- =======================================
local function convert_dec2dms_dms(coordinate)
-- === Functions =========================
coordinate = math_mod._round( coordinate * 60 * 60, 0 );
-- =======================================
local s = coordinate % 60
p = {}
coordinate = math.floor( (coordinate - s) / 60 );
local m = coordinate % 60
coordinate = math.floor( (coordinate - m) / 60 );
local d = coordinate % 360 .."°"
 
return d .. string.format( "%02d′", m ) .. string.format( "%02d″", s )
-- parse attribute variable returning desired field
function p.parseAttribute(frame)
return string.match(mw.text.decode(frame.args[1]), mw.text.decode(frame.args[2]) .. ':' .. '([^_]*)') or ''
end
 
--[[
--[[============================================================================
Helper function, convert decimal latitude or longitude to
Parse attribute variable returning heading field. If heading is a string than
degrees, minutes, and seconds format based on the specified precision.
try to convert it to an angle
]]
==============================================================================]]
local function convert_dec2dms(coordinate, firstPostfix, secondPostfix, precision)
function p.getHeading(frame)
local coord = tonumber(coordinate)
local attributes
local postfix
if frame.args[1] then
if coord >= 0 then
attributes = frame.args[1]
postfix = firstPostfix
elseif frame.args.attributes then
attributes = frame.args.attributes
else
postfix = secondPostfix
return ''
end
 
local hNum = p._getHeading(attributes)
precision = precision:lower();
if hNum == nil then
if precision == "dms" then
return ''
return convert_dec2dms_dms( math.abs( coord ) ) .. postfix;
elseif precision == "dm" then
return convert_dec2dms_dm( math.abs( coord ) ) .. postfix;
elseif precision == "d" then
return convert_dec2dms_d( math.abs( coord ) ) .. postfix;
end
return tostring(hNum)
end
 
-- Helper core function for getHeading.
--[[
function p._getHeading(attributes)
Convert DMS format into a N or E decimal coordinate
if attributes == nil then
]]
return nil
local function convert_dms2dec(direction, degrees_str, minutes_str, seconds_str)
local degrees = tonumber(degrees_str)
local minutes = tonumber(minutes_str) or 0
local seconds = tonumber(seconds_str) or 0
local factor = 1
if direction == "S" or direction == "W" then
factor = -1
end
local hStr = string.match(mw.text.decode(attributes), 'heading:([^_]*)')
local precision = 0
if hStr == nil then
if seconds_str then
return nil
precision = 5 + math.max( math_mod._precision(seconds_str), 0 );
elseif minutes_str and minutes_str ~= '' then
precision = 3 + math.max( math_mod._precision(minutes_str), 0 );
else
precision = math.max( math_mod._precision(degrees_str), 0 );
end
local hNum = tonumber( hStr )
local decimal = factor * (degrees+(minutes+seconds/60)/60)
if hNum == nil then
return string.format( "%." .. precision .. "f", decimal ) -- not tonumber since this whole thing is string based.
hStr = string.upper (hStr)
end
hNum = compass_points[hStr]
 
--[[
Checks input values to for out of range errors.
]]
local function validate( lat_d, lat_m, lat_s, long_d, long_m, long_s, source, strong )
local errors = {};
lat_d = tonumber( lat_d ) or 0;
lat_m = tonumber( lat_m ) or 0;
lat_s = tonumber( lat_s ) or 0;
long_d = tonumber( long_d ) or 0;
long_m = tonumber( long_m ) or 0;
long_s = tonumber( long_s ) or 0;
 
if strong then
if lat_d < 0 then
table.insert(errors, {source, "latitude degrees < 0 with hemisphere flag"})
end
if long_d < 0 then
table.insert(errors, {source, "longitude degrees < 0 with hemisphere flag"})
end
--[[
#coordinates is inconsistent about whether this is an error. If globe: is
specified, it won't error on this condition, but otherwise it will.
For not simply disable this check.
if long_d > 180 then
table.insert(errors, {source, "longitude degrees > 180 with hemisphere flag"})
end
]]
end
if lat_d > 90 then
table.insert(errors, {source, "latitude degrees > 90"})
end
if hNumlat_d ~=< nil-90 then
table.insert(errors, {source, "latitude degrees < -90"})
hNum = hNum%360
end
if lat_m >= 60 then
return hNum
table.insert(errors, {source, "latitude minutes >= 60"})
end
if lat_m < 0 then
table.insert(errors, {source, "latitude minutes < 0"})
end
if lat_s >= 60 then
table.insert(errors, {source, "latitude seconds >= 60"})
end
if lat_s < 0 then
table.insert(errors, {source, "latitude seconds < 0"})
end
if long_d >= 360 then
table.insert(errors, {source, "longitude degrees >= 360"})
end
if long_d <= -360 then
table.insert(errors, {source, "longitude degrees <= -360"})
end
if long_m >= 60 then
table.insert(errors, {source, "longitude minutes >= 60"})
end
if long_m < 0 then
table.insert(errors, {source, "longitude minutes < 0"})
end
if long_s >= 60 then
table.insert(errors, {source, "longitude seconds >= 60"})
end
if long_s < 0 then
table.insert(errors, {source, "longitude seconds < 0"})
end
return errors;
end
 
--[[
--[[============================================================================
parseDec
Convert degrees to degrees/minutes/seconds notation comonly used when displaying
 
coordinates.
Transforms decimal format latitude and longitude into the
Inputs:
structure to be used in displaying coordinates
1) latitude or longitude angle in degrees
]]
2) georeference precission in degrees
local function parseDec( lat, long, format )
3) language used in formating of the number
local coordinateSpec = {}
==============================================================================]]
local errors = {}
function p.deg2dms(frame)
local deg = tonumber(frame.args[1])
if not long then
local degPrec = tonumber(frame.args[2]) or 0-- precision in degrees
return nil, {{"parseDec", "Missing longitude"}}
local lang = frame.args.lang
elseif not tonumber(long) then
if not (lang and mw.language.isSupportedLanguage(lang)) then
return nil, {{"parseDec", "Longitude could not be parsed as a number: " .. long}}
lang = frame:callParserFunction("int","lang") -- get user's chosen language
end
if deg==nil then
errors = validate( lat, nil, nil, long, nil, nil, 'parseDec', false );
return frame.args[1];
coordinateSpec["dec-lat"] = lat;
coordinateSpec["dec-long"] = long;
 
local mode = coordinates.determineMode( lat, long );
coordinateSpec["dms-lat"] = convert_dec2dms( lat, "N", "S", mode) -- {{coord/dec2dms|{{{1}}}|N|S|{{coord/prec dec|{{{1}}}|{{{2}}}}}}}
coordinateSpec["dms-long"] = convert_dec2dms( long, "E", "W", mode) -- {{coord/dec2dms|{{{2}}}|E|W|{{coord/prec dec|{{{1}}}|{{{2}}}}}}}
if format then
coordinateSpec.default = format
else
coordinateSpec.default = "dec"
return p._deg2dms(deg, degPrec, lang)
end
 
return coordinateSpec, errors
end
 
--[[
--[[============================================================================
parseDMS
Helper core function for deg2dms. deg2dms can be called by templates, while
_deg2dms should be called from Lua.
Inputs:
* deg - positive coordinate in degrees
* degPrec - coordinate precission in degrees will result in different angle format
* lang - language to used when formating the number
==============================================================================]]
function p._deg2dms(deg, degPrec, lang)
local dNum, mNum, sNum, dStr, mStr, sStr, formatStr, secPrec, c, k
local Lang = mw.language.new(lang)
 
Transforms degrees, minutes, seconds format latitude and longitude
-- adjust number display based on precission
into the a structure to be used in displaying coordinates
secPrec = degPrec*3600.0 -- coordinate precission in seconds
]]
if secPrec<0.05 then -- degPrec<1.3889e-05
local function parseDMS( lat_d, lat_m, lat_s, lat_f, long_d, long_m, long_s, long_f, format )
formatStr = '%s°&nbsp;%s′&nbsp;%s″' -- use DD° MM′ SS.SS″ format
local coordinateSpec, errors, backward = {}, {}
c = 360000
elseif secPrec<0.5 then -- 1.3889e-05<degPrec<1.3889e-04
lat_f = lat_f:upper();
formatStr = '%s°&nbsp;%s′&nbsp;%s″' -- use DD° MM′ SS.S″ format
long_f = long_f:upper();
c = 36000
elseif degPrec*60.0<0.5 then -- 1.3889e-04<degPrec<0.0083
-- Check if specified backward
formatStr = '%s°&nbsp;%s′&nbsp;%s″' -- use DD° MM′ SS″ format
if lat_f == 'E' or lat_f == 'W' then
c = 3600
lat_d, long_d, lat_m, long_m, lat_s, long_s, lat_f, long_f, backward = long_d, lat_d, long_m, lat_m, long_s, lat_s, long_f, lat_f, true;
elseif degPrec<0.5 then -- 0.0083<degPrec<0.5
end
formatStr = '%s°&nbsp;%s′' -- use DD° MM′ format
c = 60
else -- if degPrec>0.5 then
formatStr = '%s°' -- use DD° format
c = 1
end
errors = validate( lat_d, lat_m, lat_s, long_d, long_m, long_s, 'parseDMS', true );
-- create degree, minute and seconds numbers and string
if not long_d then
d = c/60
return nil, {{"parseDMS", "Missing longitude" }}
k = math.floor(c*(deg%360)+0.49) -- convert float to an integer. This step HAS to be identical for all conversions to avoid incorrect results due to different rounding
elseif not tonumber(long_d) then
dNum = math.floor(k/c) % 360 -- degree number (integer in 0-360 range)
return nil, {{"parseDMS", "Longitude could not be parsed as a number:" .. long_d }}
mNum = math.floor(k/d) % 60 -- minute number (integer in 0-60 range)
sNum = 3600*(k%d) / c -- seconds number (float in 0-60 range with 0, 1 or 2 decimal digits)
dStr = Lang:formatNum(dNum) -- degree string
mStr = Lang:formatNum(mNum) -- minute string
sStr = Lang:formatNum(sNum) -- second string
if mNum<10 then
mStr = '0' ..mStr -- pad with zero if a single digit
end
if sNum<10 then
if not lat_m and not lat_s and not long_m and not long_s and #errors == 0 then
sStr = '0' ..sStr -- pad with zero if less than ten
if math_mod._precision( lat_d ) > 0 or math_mod._precision( long_d ) > 0 then
end
if lat_f:upper() == 'S' then
return string.format(formatStr, dStr, mStr, sStr);
lat_d = '-' .. lat_d;
end
if long_f:upper() == 'W' then
long_d = '-' .. long_d;
end
return parseDec( lat_d, long_d, format );
end
end
coordinateSpec["dms-lat"] = lat_d.."°"..optionalArg(lat_m,"′") .. optionalArg(lat_s,"″") .. lat_f
coordinateSpec["dms-long"] = long_d.."°"..optionalArg(long_m,"′") .. optionalArg(long_s,"″") .. long_f
coordinateSpec["dec-lat"] = convert_dms2dec(lat_f, lat_d, lat_m, lat_s) -- {{coord/dms2dec|{{{4}}}|{{{1}}}|0{{{2}}}|0{{{3}}}}}
coordinateSpec["dec-long"] = convert_dms2dec(long_f, long_d, long_m, long_s) -- {{coord/dms2dec|{{{8}}}|{{{5}}}|0{{{6}}}|0{{{7}}}}}
 
if format then
coordinateSpec.default = format
else
coordinateSpec.default = "dms"
end
 
return coordinateSpec, errors, backward
end
 
--[[
--[[============================================================================
Check the input arguments for coord to determine the kind of data being provided
Format coordinate location string, by creating and joining DMS strings for
and then make the necessary processing.
latutude and longitude. Also convert precission from meters to degrees.
]]
INPUTS:
local function formatTest(args)
* lat = latitude in degrees
local result, errors
* lon = longitude in degrees
local backward, primary = false, false
* lang = language code
 
* prec = geolocation precission in meters
local function getParam(args, lim)
==============================================================================]]
local ret = {}
function p.lat_lon(frame)
for i = 1, lim do
local lat = tonumber(frame.args.lat)
ret[i] = args[i] or ''
local lon = tonumber(frame.args.lon)
local prec = math.abs(tonumber(frame.args.prec) or 0) -- location precision in meters
if lon then -- get longitude t0 be in -180 to 180 range
lon=lon%360
if lon>180 then
lon = lon-360
end
return table.concat(ret, '_')
end
local lang = frame.args.lang
if not (lang and mw.language.isSupportedLanguage(lang))args[1] then
-- no lat logic
lang = frame:callParserFunction("int","lang") -- get user's chosen language
return errorPrinter( {{"formatTest", "Missing latitude"}} )
end
ifelseif lat==nilnot or lon==niltonumber(args[1]) then
-- bad lat logic
return NoLatLonString
return errorPrinter( {{"formatTest", "Unable to parse latitude as a number:" .. args[1]}} )
elseif not args[4] and not args[5] and not args[6] then
-- dec logic
result, errors = parseDec(args[1], args[2], args.format)
if not result then
return errorPrinter(errors);
end
result.param = table.concat({args[1], 'N', args[2] or '', 'E', args[3] or ''}, '_')
elseif dmsTest(args[4], args[8]) then
-- dms logic
result, errors, backward = parseDMS(args[1], args[2], args[3], args[4],
args[5], args[6], args[7], args[8], args.format)
if args[10] then
table.insert(errors, {'formatTest', 'Extra unexpected parameters'})
end
if not result then
return errorPrinter(errors)
end
result.param = getParam(args, 9)
elseif dmsTest(args[3], args[6]) then
-- dm logic
result, errors, backward = parseDMS(args[1], args[2], nil, args[3],
args[4], args[5], nil, args[6], args['format'])
if args[8] then
table.insert(errors, {'formatTest', 'Extra unexpected parameters'})
end
if not result then
return errorPrinter(errors)
end
result.param = getParam(args, 7)
elseif dmsTest(args[2], args[4]) then
-- d logic
result, errors, backward = parseDMS(args[1], nil, nil, args[2],
args[3], nil, nil, args[4], args.format)
if args[6] then
table.insert(errors, {'formatTest', 'Extra unexpected parameters'})
end
if not result then
return errorPrinter(errors)
end
result.param = getParam(args, 5)
else
-- Error
local nsew = langSwitch(i18n.NSEW, lang) -- find set of localized translation of N, S, W and E in the desired language
return errorPrinter({{"formatTest", "Unknown argument format"}})
local SN, EW, latStr, lonStr, lon2m, lat2m, phi
end
if lat<0 then SN = nsew.S else SN = nsew.N end -- choose S or N depending on latitude degree sign
result.name = args.name
if lon<0 then EW = nsew.W else EW = nsew.E end -- choose W or E depending on longitude degree sign
lat2m=1
local extra_param = {'dim', 'globe', 'scale', 'region', 'source', 'type'}
lon2m=1
for _, v in ipairs(extra_param) do
if prec>0 then -- if user specified the precission of the geo location...
if args[v] then
phi = math.abs(lat)*math.pi/180 -- latitude in radiants
table.insert(errors, {'formatTest', 'Parameter: "' .. v .. '=" should be "' .. v .. ':"' })
lon2m = 6378137*math.cos(phi)*math.pi/180 -- see https://en.wikipedia.org/wiki/Longitude
lat2m = 111000 -- average latitude degree size in meters
end
latStr = p._deg2dms(math.abs(lat), prec/lat2m, lang) -- Convert latitude degrees to degrees/minutes/seconds
lonStr = p._deg2dms(math.abs(lon), prec/lon2m, lang) -- Convert longitude degrees to degrees/minutes/seconds
return string.format('%s&nbsp;%s, %s&nbsp;%s', latStr, SN, lonStr, EW)
--return string.format('<span class="latitude">%s %s</span>, <span class="longitude">%s %s</span>', latStr, SN, lonStr, EW)
end
end
local ret = specPrinter(args, result)
 
if #errors > 0 then
--[[============================================================================
ret = ret .. ' ' .. errorPrinter(errors) .. '[[Category:Pages with malformed coordinate tags]]'
Create URL for different sites.
INPUTS:
* site = Possinle sites: GeoHack, GoogleEarth, Proximityrama,
OpenStreetMap, GoogleMaps (for Earth, Mars and Moon)
* globe = Possible options: Earth, Mars or Moon. Venus, Mercury, Titan,
Ganymede are also supported but are unused as of 2013.
* lat = latitude string or number
* lon = longitude string or number
* lang = language code
* attributes = attributes to be passed to GeoHack
==============================================================================]]
function p.externalLink(frame)
args = frame.args
local lang = frame.args.lang
if not (lang and mw.language.isSupportedLanguage(lang)) then
lang = frame:callParserFunction("int","lang") -- get user's chosen language
end
return ret, backward
return p._externalLink(args.site or 'GeoHack', args.globe or 'Earth', args.lat, args.lon, lang, args.attributes or '')
end
--[[============================================================================
Helper core function for externalLink. Create URL for different sites:
INPUTS:
* site = Possinle sites: GeoHack, GoogleEarth, Proximityrama,
OpenStreetMap, GoogleMaps (for Earth, Mars and Moon)
* globe = Possible options: Earth, Mars or Moon. Venus, Mercury, Titan,
Ganymede are also supported but are unused as of 2013.
* latStr = latitude string or number
* lonStr = longitude string or number
* lang = language code
* attributes = attributes to be passed to GeoHack
==============================================================================]]
function p._externalLink(site, globe, latStr, lonStr, lang, attributes, level)
local URLstr = SiteURL[site];
level = level or 1
local pageName = mw.uri.encode( mw.title.getCurrentTitle().prefixedText, 'WIKI' )
pageName = mw.ustring.gsub( pageName, '%%', '%%%%')
 
--[[
if site == 'GoogleMaps' then
Generate Wikidata tracking categories.
URLstr = SiteURL.GoogleMaps[globe]
]]
elseif site == 'GeoHack' then
local function makeWikidataCategories()
attributes = string.format('globe:%s_%s', globe, attributes)
local ret
URLstr = mw.ustring.gsub( URLstr, '$attr', attributes)
if mw.wikibase and current_page.namespace == 0 then
local entity = mw.wikibase.getEntityObject()
if entity and entity.claims and entity.claims.P625 and entity.claims.P625[1] then
local snaktype = entity.claims.P625[1].mainsnak.snaktype
if snaktype == 'value' then
-- coordinates exist both here and on Wikidata, and can be compared.
ret = 'Coordinates on Wikidata'
elseif snaktype == 'somevalue' then
ret = 'Coordinates on Wikidata set to unknown value'
elseif snaktype == 'novalue' then
ret = 'Coordinates on Wikidata set to no value'
end
else
-- We have to either import the coordinates to Wikidata or remove them here.
ret = 'Coordinates not on Wikidata'
end
end
if ret then
return string.format('[[Category:%s]]', ret)
else
return ''
end
URLstr = mw.ustring.gsub( URLstr, '$lat' , latStr)
URLstr = mw.ustring.gsub( URLstr, '$lon' , lonStr)
URLstr = mw.ustring.gsub( URLstr, '$lang' , lang)
URLstr = mw.ustring.gsub( URLstr, '$level', level)
URLstr = mw.ustring.gsub( URLstr, '$page' , pageName)
URLstr = mw.ustring.gsub( URLstr, '+', '')
URLstr = mw.ustring.gsub( URLstr, ' ', '_')
return URLstr
end
 
--[[
--[[============================================================================
link
Adjust GeoHack attributes depending on the template that calls it
 
INPUTS:
Simple function to export the coordinates link for other uses.
* attributes = attributes to be passed to GeoHack
 
* mode = set by each calling template
Usage:
==============================================================================]]
{{#invoke:Coordinates | link }}
function p.alterAttributes(attributes, mode)
-- indicate which template called it
]]
if mode=='camera' then -- Used by {{Location}} and {{Location dec}}
function coordinates.link(frame)
if string.find(attributes, 'type:camera')==nil then
return coord_link;
attributes = 'type:camera_' .. attributes
end
elseif mode=='object'or mode =='globe' then -- Used by {{Object location}}
if string.find(attributes, 'class:object')==nil then
attributes = 'class:object_' .. attributes
end
elseif mode=='inline' then -- Used by {{Inline coordinates}} (actually that template does not set any attributes at the moment)
elseif mode=='user' then -- Used by {{User location}}
attributes = 'type:user_location'
elseif mode=='institution' then --Used by {{Institution/coordinates}} (categories only)
attributes = 'type:institution'
end
return attributes
end
 
--[[
dec2dms
 
Wrapper to allow templates to call dec2dms directly.
 
Usage:
{{#invoke:Coordinates | dec2dms | decimal_coordinate | positive_suffix |
negative_suffix | precision }}
decimal_coordinate is converted to DMS format. If positive, the positive_suffix
--[[============================================================================
is appended (typical N or E), if negative, the negative suffix is appended. The
Create link to GeoHack tool which displays latitude and longitude coordinates
specified precision is one of 'D', 'DM', or 'DMS' to specify the level of detail
in DMS format
to use.
INPUTS:
]]
* globe = Possible options: Earth, Mars or Moon. Venus, Mercury, Titan,
coordinates.dec2dms = makeInvokeFunc('_dec2dms')
Ganymede are also supported but are unused as of 2013.
function coordinates._dec2dms(args)
* lat = latitude in degrees
local coordinate = args[1]
* lon = longitude in degrees
local firstPostfix = args[2] or ''
* lang = language code
local secondPostfix = args[3] or ''
* prec = geolocation precission in meters
local precision = args[4] or ''
* attributes = attributes to be passed to GeoHack
 
==============================================================================]]
return convert_dec2dms(coordinate, firstPostfix, secondPostfix, precision)
function p.GeoHack_link(frame)
end
-- create link and coordintate string
 
local latlon = p.lat_lon(frame)
--[[
if latlon==NoLatLonString then
Helper function to determine whether to use D, DM, or DMS
return latlon
format depending on the precision of the decimal input.
]]
function coordinates.determineMode( value1, value2 )
local precision = math.max( math_mod._precision( value1 ), math_mod._precision( value2 ) );
if precision <= 0 then
return 'd'
elseif precision <= 2 then
return 'dm';
else
return 'dms';
frame.args.site = 'GeoHack'
local url = p.externalLink(frame)
return string.format('<span class="plainlinksneverexpand">[%s %s]</span>', url, latlon) --<span class="plainlinks nourlexpansion">
end
end
 
--[[
dms2dec
 
Wrapper to allow templates to call dms2dec directly.
 
Usage:
{{#invoke:Coordinates | dms2dec | direction_flag | degrees |
minutes | seconds }}
Converts DMS values specified as degrees, minutes, seconds too decimal format.
direction_flag is one of N, S, E, W, and determines whether the output is
positive (i.e. N and E) or negative (i.e. S and W).
]]
coordinates.dms2dec = makeInvokeFunc('_dms2dec')
function coordinates._dms2dec(args)
local direction = args[1]
local degrees = args[2]
local minutes = args[3]
local seconds = args[4]
 
return convert_dms2dec(direction, degrees, minutes, seconds)
end
 
--[[
--[[============================================================================
coord
Create full external links section of {{Location}} or {{Object location}}
 
templates, based on:
Main entry point for Lua function to replace {{coord}}
* globe = Possible options: Earth, Mars or Moon. Venus, Mercury, Titan, Ganymede are also supported but are unused as of 2013.
 
* mode = Possible options:
Usage:
- camera - call from {{location}}
{{#invoke:Coordinates | coord }}
- object - call from {{Object location}}
{{#invoke:Coordinates | coord | lat | long }}
- globe - call from {{Globe location}}
{{#invoke:Coordinates | coord | lat | lat_flag | long | long_flag }}
* lat = latitude in degrees
...
* lon = longitude in degrees
* lang = language code
* namespace = namespace name: File, Category, (Gallery)
==============================================================================]]
function p.externalLinksSection(frame)
local args = frame.args
local lang = frame.args.lang
if not (lang and mw.language.isSupportedLanguage(lang)) then
lang = frame:callParserFunction("int","lang") -- get user's chosen language
end
if not args.namespace then
args.namespace = mw.title.getCurrentTitle().namespace
end
Refer to {{coord}} documentation page for many additional parameters and
local str, link1, link2
configuration options.
if args.globe=='Earth' and args.namespace~="Category" then -- Earth locations for files will have 2 links
link1 = p._externalLink('OpenStreetMap1', 'Earth', args.lat, args.lon, lang, '')
Note: This function provides the visual display elements of {{coord}}. In
link2 = p._externalLink('GoogleEarth' , 'Earth', args.lat, args.lon, lang, '')
order to load coordinates into the database, the {{#coordinates:}} parser
str = string.format('[%s %s] - [%s %s]',
function must also be called, this is done automatically in the Lua
link1, langSwitch(i18n.OpenStreetMaps, lang),
version of {{coord}}.
link2, langSwitch(i18n.GoogleEarth, lang))
]]
elseif args.globe=='Earth' and args.namespace=="Category" then -- Earth locations for categories will have 4 links
coordinates.coord = makeInvokeFunc('_coord')
link1 = p._externalLink('OpenStreetMap2', 'Earth', args.lat, args.lon, lang, '', args.catRecurse)
function coordinates._coord(args)
link2 = p._externalLink('GoogleMaps' , 'Earth', args.lat, args.lon, lang, '', args.catRecurse)
if (not args[1] or not tonumber(args[1])) and not args[2] and mw.wikibase.getEntityObject() then
link3 = p._externalLink('GoogleEarth' , 'Earth', args.lat, args.lon, lang, '')
args[3] = args[1]; args[1] = nil
link4 = p._externalLink('Proximityrama' , 'Earth', args.lat, args.lon, lang, '')
local entity = mw.wikibase.getEntityObject()
str = string.format('[%s %s] - [%s %s] - [%s %s] - [%s %s]',
if entity
link1, langSwitch(i18n.OpenStreetMaps, lang),
and entity.claims
link2, langSwitch(i18n.GoogleMaps, lang),
and entity.claims.P625
link3, langSwitch(i18n.GoogleEarth, lang),
and entity.claims.P625[1].mainsnak.snaktype == 'value'
link4, langSwitch(i18n.Proximityrama, lang))
then
elseif args.globe=='Mars' or args.globe=='Moon' then
local precision = entity.claims.P625[1].mainsnak.datavalue.value.precision
link1 = p._externalLink('GoogleMaps', args.globe, args.lat, args.lon, lang, '')
args[1]=entity.claims.P625[1].mainsnak.datavalue.value.latitude
str = string.format('[%s %s]', link1, langSwitch(i18n.GoogleMaps, lang))
args[2]=entity.claims.P625[1].mainsnak.datavalue.value.longitude
if precision then
precision=-math_mod._round(math.log(precision)/math.log(10),0)
args[1]=math_mod._round(args[1],precision)
args[2]=math_mod._round(args[2],precision)
end
end
end
local contents, backward = formatTest(args)
return str
local Notes = args.notes or ''
end
local Display = args.display and args.display:lower() or 'inline'
 
local function isInline(s)
--[[============================================================================
-- Finds whether coordinates are displayed inline.
Core section of template:Location, template:Object location and template:Globe location.
return s:find('inline') ~= nil or s == 'i' or s == 'it' or s == 'ti'
This method requires several arguments to be passed to it or it's parent metchod/template:
* globe = Possible options: Earth, Mars or Moon. Venus, Mercury, Titan, Ganymede are also supported but are unused as of 2013.
* mode = Possible options:
- camera - call from {{location}}
- object - call from {{Object location}}
- globe - call from {{Globe location}}
* lat = latitude in degrees
* lon = longitude in degrees
* attributes = attributes
* lang = language code
* namespace = namespace: File, Category, Gallery
* prec = geolocation precission in meters
==============================================================================]]
function p.LocationTemplateCore(frame)
-- prepare arguments
args = frame.args
if not args or not args.lat then -- if no arguments provided than use parent arguments
args = mw.getCurrentFrame():getParent().args
end
local function isInTitle(s)
if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then
-- Finds whether coordinates are displayed in the title.
args.lang = frame:callParserFunction("int","lang") -- get user's chosen language
return s:find('title') ~= nil or s == 't' or s == 'it' or s == 'ti'
end
if not (args.namespace) then -- if namespace not provided than look it up
local function coord_wrapper(in_args)
args.namespace = mw.title.getCurrentTitle().namespace
-- Calls the parser function {{#coordinates:}}.
return mw.getCurrentFrame():callParserFunction('#coordinates', in_args) or ''
end
if args.namespace=='' then -- if empty than it is a gallery
local text = ''
args.namespace = 'Gallery'
if isInline(Display) then
text = text .. displayinline(contents, Notes)
end
if isInTitle(Display) then
local bare = yesno(args.bare,false)
text = text
local Status = 'primary' -- used by {{#coordinates:}}
.. displaytitle(contents, Notes)
if yesno(args.secondary,false) then
.. makeWikidataCategories()
Status = 'secondary'
end
if not args.nosave then
args.attributes = p.alterAttributes(args.attributes or '', args.mode)
local page_title, count = mw.title.getCurrentTitle(), 1
if backward then
-- Convert coordinates from string to numbers
local lattmp = tonumber(args.lat){}
while not string.find((args[count-1] or ''), '[EW]') do tmp[count] = (args[count] or ''); count = count+1 end
local lon = tonumber(args.lon)
tmp.count = count; count = 2*(count-1)
if lon then -- get longitude to be in -180 to 180 range
while count >= tmp.count do table.insert(tmp, 1, (args[count] or '')); count = count-1 end
lon=lon%360
for i, v in ipairs(tmp) do args[i] = v end
if lon>180 then
else
lon = lon-360
while count <= 9 do args[count] = (args[count] or ''); count = count+1 end
end
if isInTitle(Display) and not page_title.isTalkPage and page_title.subpageText ~= 'doc' and page_title.subpageText ~= 'testcases' then args[10] = 'primary' end
args.notes, args.format, args.display = nil
text = text .. coord_wrapper(args)
end
return text
end
-- If wikidata link provided than compare coordinates
local Categories, geoMicroFormat, coorTag, wikidata_link = '', '', '', ''
if args.wikidata and args.wikidata~='' then
local dist_str
-- if lat/lon is not provided but we are given wikidata q-code than look up the coordinates
lat, lon, q, Categories, dist_str = mergeWithWikidata(args.wikidata, lat, lon)
wikidata_link = string.format("\n[[File:Wikidata-logo.svg|20px|Edit coordinates on Wikidata%s|link=wikidata:%s]]", dist_str, q);
end
 
--[[
args.lat = string.format('%010.6f', lat or 0)
coord2text
args.lon = string.format('%011.6f', lon or 0)
frame.args = args
 
Extracts a single value from a transclusion of {{Coord}}.
-- Categories, {{#coordinates}} and geoMicroFormat will be only added to File, Category and Gallery pages
IF THE GEOHACK LINK SYNTAX CHANGES THIS FUNCTION MUST BE MODIFIED.
if (args.namespace == 'File' or args.namespace == 'Category' or args.namespace == 'Gallery') then
if lat and lon then -- if lat and lon are numbers...
if lat==0 and lon==0 then -- lat=0 and lon=0 is a common issue when copying from flickr and other sources
Categories = Categories .. CoorCat.default
end
if frame.args.attributes and string.find(frame.args.attributes, '=') then
Categories = Categories .. CoorCat.attribute
end
if args.error=='1' or (math.abs(lat)>90) then -- check for errors ({{#coordinates:}} also checks for errors )
Categories = Categories .. CoorCat.erroneous
end
local cat = CoorCat[args.namespace]
if cat then -- add category based on namespace
Categories = Categories .. cat
end
-- if not earth than add a category for each globe
if args.mode and args.globe and args.mode=='globe' and args.globe~='Earth' then
Categories = Categories .. string.format(CoorCat[args.mode], args.globe)
end
-- add <span class="geo"> Geo (microformat) code: it is included for machine readability
geoMicroFormat = string.format('<span class="geo" style="display:none">%10.6f; %11.6f</span>',lat, lon)
-- add {{#coordinates}} tag, see https://www.mediawiki.org/wiki/Extension:GeoData
if args.namespace == 'File' and Status == 'primary' and args.mode=='camera' then
coorTag = string.format('{{#coordinates:primary|%10.6f|%11.6f|%s}}', lat, lon, args.attributes)
coorTag = frame:preprocess(coorTag)
end
else -- if lat and lon are not numbers then add error category
Categories = Categories .. CoorCat.erroneous
end
 
Usage:
end
 
{{#invoke:Coordinates | coord2text | {{Coord}} | parameter }}
-- Call helper functions to render different parts of the template
 
local coor, info_link, inner_table, heading, OSM = '','','','','','',''
Valid values for the second parameter are: lat (signed integer), long (signed integer), type, scale, dim, region, globe, source
coor = p.GeoHack_link(frame) -- the p and link to GeoHack
 
heading = p._getHeading(frame.args.attributes) -- get heading arrow section
]]
if heading then
function coordinates.coord2text(frame)
local k = math.fmod(math.floor(0.5+math.fmod(heading+360,360)/11.25),32)+1
if frame.args[1] == '' or frame.args[2] == '' or not frame.args[2] then return nil end
local fname = heading_icon[k]
frame.args[2] = mw.text.trim(frame.args[2])
coor = string.format('%s&nbsp;&nbsp;<span title="%s°">[[%s|25px|link=|alt=Heading=%s°]]</span>', coor, heading, fname, heading)
if frame.args[2] == 'lat' or frame.args[2] == 'long' then
end
local result, negative = mw.text.split((mw.ustring.match(frame.args[1],'[%.%d]+°[NS] [%.%d]+°[EW]') or ''), ' ')
if args.globe=='Earth' then
localif iconframe.args[2] == 'markerlat' then
result, negative = result[1], 'S'
if args.mode=='camera' then
else
icon = 'camera'
result, negative = result[2], 'W'
end
result = mw.text.split(result, '°')
OSM = frame:preprocess(add_maplink(args.lat, args.lon, icon, '[[File:Openstreetmap logo.svg|20px|link=|Kartographer map based on OpenStreetMap.]]')) -- fancy link to OSM
if result[2] == negative then result[1] = '-'..result[1] end
end
return result[1]
external_link = p.externalLinksSection(frame) -- external link section
if external_link and args.namespace == 'File' then
external_link = langSwitch(i18n.LocationTemplateLinkLabel, args.lang) .. ' ' .. external_link -- header of the link section for {{location}} template
elseif external_link then
external_link = langSwitch(i18n.ObjectLocationTemplateLinkLabel, args.lang) .. ' ' .. external_link -- header of the link section for {{Object location}} template
end
info_link = string.format('[[File:Circle-information.svg|18x18px|alt=info|link=%s]]', langSwitch(i18n.COM_GEO, args.lang) )
inner_table = string.format('<td style="border:none;">%s&nbsp;%s</td><td style="border:none;">%s</td><td style="border:none;">%s%s%s</td>',
coor, OSM, external_link or '', info_link, wikidata_link, geoMicroFormat)
-- combine strings into a table
local templateText
if bare then
templateText = string.format('<table style="width:100%%"><tr>%s</tr></table>', inner_table)
else
return mw.ustring.match(frame.args[1], 'params=.-_'..frame.args[2]..':(.-)[ _]')
-- choose name of the field
end
local field_name = 'Location'
end
if args.mode=='camera' then
 
field_name = langSwitch(i18n.CameraLocation, args.lang)
--[[
elseif args.mode=='object' then
coordinsert
field_name = langSwitch(i18n.ObjectLocation, args.lang)
 
elseif args.mode=='globe' then
Injects some text into the Geohack link of a transclusion of {{Coord}} (if that text isn't already in the transclusion). Outputs the modified transclusion of {{Coord}}.
field_list = langSwitch(i18n.GlobeLocation, args.lang)
IF THE GEOHACK LINK SYNTAX CHANGES THIS FUNCTION MUST BE MODIFIED.
if args.globe and i18n.GlobeLocation['en'][args.globe] then -- verify globe is provided and is recognized
 
field_name = field_list[args.globe]
Usage:
end
 
{{#invoke:Coordinates | coordinsert | {{Coord}} | parameter:value | parameter:value | … }}
 
Do not make Geohack unhappy by inserting something which isn't mentioned in the {{Coord}} documentation.
 
]]
function coordinates.coordinsert(frame)
for i, v in ipairs(frame.args) do
if i ~= 1 then
if not mw.ustring.find(frame.args[1], (mw.ustring.match(frame.args[i], '^(.-:)') or '')) then frame.args[1] = mw.ustring.gsub(frame.args[1], '(params=.-)_? ', '%1_'..frame.args[i]..' ') end
end
--Create HTML text
local dir, text_align
if mw.language.new( args.lang ):isRTL() then
dir = 'rtl'
text_align = 'right'
else
dir = 'ltr'
text_align = 'left'
end
local style = string.format('class="toccolours mw-content-%s layouttemplate commons-file-information-table" cellpadding="2" style="width: 100%%; direction:%s;" lang="%s"',
args.lang, dir, text_align, args.lang)
templateText = string.format('<table lang="%s" %s><tr><th class="type fileinfo-paramfield">%s</th>%s</tr></table>', args.lang, style, field_name, inner_table)
end
return frame.args[1]
return templateText .. Categories .. coorTag
end
 
return pcoordinates