« Module:Coordinates » : différence entre les versions
Apparence
Modèle:Infobox>Orlodrim |
Modèle:Infobox>Orlodrim Remplacement par la version de Zolo à partir de Module:Coordinates/Test |
||
| Ligne 1 : | Ligne 1 : | ||
local math_mod = require( "Module:Math" ) | |||
local p = {} | |||
{ | local i18n = { | ||
N = ' N', | |||
Nlong = ' Nord', | |||
W = ' O', | |||
Wlong = ' Ouest', | |||
E = ' E', | |||
Elong = ' Est', | |||
S = ' S', | |||
Slong = ' Sud', | |||
degrees = '° ', | |||
minutes = '\′ ', | |||
seconds = '″ ', | |||
geohackurl = 'http://tools.wmflabs.org/geohack/geohack.php?language=fr', | |||
tooltip = 'Cartes, vues aériennes et autres données pour cet endroit', | |||
errorcat = 'Pages avec des balises de coordonnées mal formées', | |||
sameaswikidata = 'Page avec coordonnées similaires sur Wikidata', | |||
notaswikidata = 'Page avec coordonnées différentes sur Wikidata', | |||
throughwikidata = 'Page géolocalisée par Wikidata', | |||
} | |||
{{ | local globedata = { | ||
--[[ notes: | |||
radius in kilometers (especially imprecise for non spheric bodies) | |||
defaultdisplay is currently disabled, activate it ? | |||
]]-- | |||
ariel = {radius = 580, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
callisto = {radius = 2410, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
ceres = {radius = 470, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
deimos = {radius = 7, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
dione = {radius = 560, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
enceladus = {radius = 255, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
ganymede = {radius = 1631, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
earth = {radius = 6371, defaultdisplay = 'dms', trackingcat = 'Article géolocalisé sur Terre'}, | |||
europe = {radius = 1561, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
hyperion = {radius = 140, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
iapetus = {radius = 725, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
['io'] = {radius = 1322, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
jupiter = {radius = 68911, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
mars = {radius = 3389.5, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé sur Mars' }, | |||
mercury = {radius = 2439.7, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
mimas = {radius = 197, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
miranda = {radius = 335, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
moon = {radius = 1736, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé sur la Lune'}, | |||
neptune = {radius = 24553, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
oberon = {radius = 761, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
phoebe = {radius = 110, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
phobos = {radius = 11, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
rhea = {radius = 765, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
saturn = {radius = 58232, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
titan = {radius = 2575.5, defaultdisplay = 'dec west', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
tethys = {radius = 530, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
titania = {radius = 394, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
triton = {radius = 1353, defaultdisplay = 'dec west', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
umbriel = {radius = 584, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
uranus = {radius = 25266, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
venus = {radius = 6051.8, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}, | |||
vesta = {radius = 260, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'} | |||
} | |||
local wikidatathreshold = 10 -- si la distance entre coordonnées Wikipédia et Wikidata dépasse se seuil (en kilomètes), une catégorie de maintenance est ajoutée | |||
]] | ---------------------------------------- | ||
--Error handling | |||
--[[ Notes: | |||
when errors occure a new error message is concatenated to errorstring | |||
an error message contains an error category with a sortkey | |||
For major errors, it can also display an error message (the error message will the usually be returned and the function terminated) | |||
More minor errors do only add a category, so that readers are not bothered with error texts | |||
sortkeys: | |||
* A: invalid latitude, longitude or direction | |||
* B: invalid globe | |||
* C: something wrong with other parameters | |||
]]-- | |||
errorstring = '' | |||
function makeerror(args) | |||
local errormessage = '' | |||
if args.message then | |||
function | errormessage = '<strong class="error">Coordonnées: ' .. args.message .. '</strong>' | ||
end | |||
local errorcat = '' | |||
if mw.title.getCurrentTitle().namespace == 0 then | |||
errorcat = makecat(i18n.errorcat, args.sortkey) | |||
end | |||
errorstring = errormessage .. errorcat -- reinitializes the string to avoid absurdly long messages | |||
return nil | |||
end | end | ||
function showerrors() | |||
return errorstring | |||
end | end | ||
------------------------------------------- | |||
-- | function makecat(cat, sortkey) | ||
return '[[Category:' .. cat .. '|' .. (sortkey or '*') .. ']]' | |||
end | end | ||
--[[ | ---------------------------------------- | ||
-- Distance computation | |||
function p._distance(a, b, globe) -- calcule la [[distance orthodromique]] en kilomètres entre deux points du globe | |||
globe = string.lower(globe or 'earth') | |||
-- check arguments and converts degreees to radians | |||
local latA, latB, longA, longB = a.latitude, b.latitude, a.longitude, b.longitude | |||
if not latA or not latB or not longA or not longB then return | |||
error('coordinates missing, can\'t compute distance') | |||
end | |||
if type(latA) ~= 'number' or type(latB) ~= 'number' or type(longA) ~= 'number' or type(longB) ~= 'number' then | |||
error('coordinates are not numeric, can\'t compute distance') | |||
end | |||
-- distance angulaire en radians | |||
local convratio = math.pi / 180 -- convertit en radians | |||
latA, latB, longA, longB = convratio * latA, convratio * latB, convratio * longA, convratio * longB | |||
local angle = math.acos(math.sin(latA) * math.sin(latB) + math.cos(latA) * math.cos(latB) * math.cos(longB - longA)) | |||
-- convertit en km en fonction du globe | |||
if not globe or not globedata[globe] then | |||
return error('globe: ' .. globe .. 'is not supported') | |||
end | |||
radius = globedata[globe].radius | |||
return radius * angle | |||
end | end | ||
function p.distance(frame) | |||
local args = frame.args | |||
return p._distance( | |||
{latitude = tonumber(args.latitude1), longitude = tonumber(args.longitude1)}, | |||
{latitude = tonumber(args.latitude2), longitude = tonumber(args.longitude2)}, | |||
args.globe) | |||
end | end | ||
------------------------ | |||
--HTML builder for a geohack link | |||
local function buildHTML(decLat, decLong, dmsLat, dmsLong, globe, displayformat, displayinline, displaytitle, objectname, extraparams) | |||
function | local htmlBuilder = require("Module:HtmlBuilder") | ||
local root, text, url, noprint | |||
local | extraparams = extraparams or '' | ||
-- geohack url and parameters | |||
local decimalcoords = p.displaydec(decLat, decLong, displayformat) | |||
local geohacklatitude, geohacklongitude | |||
-- format latitude and longitude for the URL | |||
if | if tonumber(decLat) < 0 then | ||
geohacklatitude = tostring(-tonumber(decLat)) .. '_S' | |||
else | |||
geohacklatitude = decLat .. '_N' | |||
end | |||
if tonumber(decLong) < 0 then | |||
geohacklongitude = tostring(-tonumber(decLong)) .. '_W' | |||
else | |||
geohacklongitude = decLong .. '_E' | |||
end | |||
-- prepares the 'paramss=' parameter | |||
local geohackparams = geohacklatitude .. '_' .. geohacklongitude .. '_' ..extraparams | |||
-- concatenate parameteres for geohack | |||
local url = i18n.geohackurl .. | |||
"&pagename=" .. mw.uri.encode(mw.title.getCurrentTitle().prefixedText, "WIKI") .. | |||
"¶ms=" .. geohackparams .. | |||
(objectname and ("&title=" .. mw.uri.encode(objectname)) or "") | |||
root = htmlBuilder.create() | |||
root | |||
.tag("span") | |||
.addClass("plainlinks nourlexpansion") | |||
.wikitext("[" .. url) | |||
.tag("span") | |||
.addClass(string.sub(displayformat,1,3) == "dec" and "geo-nondefault" or "geo-default") | |||
.tag("span") | |||
.addClass("geo-dms") | |||
.attr("title", i18n.tooltip) | |||
.tag("span") | |||
.addClass("latitude") | |||
.wikitext(p.displaydmsdimension(dmsLat, displayformat)) | |||
.done() | |||
.wikitext(" ") | |||
.tag("span") | |||
.addClass("longitude") | |||
.wikitext(p.displaydmsdimension(dmsLong, displayformat)) | |||
.done() | |||
.done() | |||
.done() | |||
.tag("span") | |||
.addClass("geo-multi-punct") | |||
.wikitext(" / ") | |||
.done() | |||
.tag("span") | |||
.addClass(string.sub(displayformat,1,3) == 'dec' and "geo-default" or "geo-nondefault") | |||
.wikitext(objectname and "<span class=\"vcard\">" or "") | |||
.tag("span") | |||
.addClass("geo-dec") | |||
.attr("title", i18n.tooltip) | |||
.wikitext(decimalcoords) | |||
.done() | |||
.wikitext(objectname and ("<span style=\"display:none\"> (<span class=\"fn org\">" .. | |||
objectname .. "</span>)</span></span>") or "") | |||
.done() | |||
.wikitext("]") | |||
.done() | |||
--[ | -- formatta il risultato a seconda di args["display"] (nil, "inline", "title", "inline,title") | ||
text = tostring(root) | |||
noprint = displayinline and "class=\"noprint\" " or "" | |||
htmlTitle = "<span style=\"font-size: small;\"><span " .. noprint .. "id=\"coordinates\">" | |||
return (displayinline and text or "") .. | |||
(displaytitle and (htmlTitle .. text .. "</span></span>") or "") | |||
end | |||
-- Fonctions de manipualation/coonversion des coordonnées | |||
function p._dec2dms(dec, coordtype, precision) -- type: latitude or longitude | |||
local dec = tonumber(dec) | |||
local dms = {} | |||
-- precision | |||
if precision and precision ~= '' and precision ~= 'd' and precision ~= 'dm' and precision ~= 'dms' then | |||
return makeerror({sortkey = 'C'}) | |||
end | |||
if not precision then | |||
precision = math_mod._precision(dec) | |||
if precision <= 0 then | |||
precision = 'd' | |||
elseif precision <= 2 then | |||
precision = 'dm'; | |||
else | |||
precision = 'dms'; | |||
end | |||
end -- et fractions de secondes ? | |||
if precision ~= 'd' and precision ~= 'dm' and precision ~= 'dms' then | |||
makeerror({message = 'invalid precision in function dec2dms', sortkey = 'C'}) | |||
end | |||
-- direction | |||
if coordtype == 'latitude' then | |||
if dec < 0 then | |||
direction = 'S' | |||
else | |||
direction = 'N' | |||
end | |||
elseif coordtype == 'longitude' then | |||
if dec < 0 then | |||
direction = 'W' | |||
else | |||
direction = 'E' | |||
end | |||
end | |||
-- conversion | |||
dec = math.abs(dec) -- les coordonnées en dms sont toujours positives | |||
if precision == 'dms' then | |||
dec = math_mod._round( dec * 60 * 60, 0 ) | |||
seconds = dec % 60 | |||
dec = (dec - seconds) / 60 / 60 | |||
end | |||
if precision == 'dm' or precision == 'dms' then | |||
dec = math_mod._round( dec * 60, 0 ) | |||
minutes = dec % 60 | |||
dec = (dec - minutes) / 60 | |||
end | |||
degrees = math_mod._round(dec, 0) | |||
return builddmsdimension(degrees, minutes, seconds, direction) | |||
end | |||
function p.dec2dms(frame) -- legacy function somewhat cumbersome syntax | |||
args = frame.args | |||
local dec = args[1] | |||
local precision = string.lower(args[4]) | |||
local displayformat, coordtype | |||
if args[2] == 'N' or 'Nord' then | |||
coordtype = 'latitude' | |||
else | |||
coordtype = 'longitude' | |||
end | |||
if args[2] == 'Nord' or args[2] == 'Est' or args[2] == 'Ouest' then | |||
displayformat = 'dms long' | |||
end | |||
local coordobject = p._dec2dms(dec, coordtype, precision) | |||
return p.displaydmsdimension(coordobject, displayformat) .. showerrors() | |||
end | |||
function p._dms2dec(dmsobject) -- transforme une table degré minute secondes en nombre décimal | |||
local direction, degrees, minutes, seconds = dmsobject.direction, dmsobject.degrees, dmsobject.minutes, dmsobject.seconds | |||
local factor = 0 | |||
local precision = 0 | |||
if not minutes then minutes = 0 end | |||
if not seconds then seconds = 0 end | |||
if direction == "N" or direction == "E" then | |||
factor = 1 | |||
elseif direction == "W" or direction == "S" then | |||
factor = -1 | |||
elseif not direction then | |||
makeerror({message = 'no cardinal direction found in coordinates', sortkey = 'A'}) | |||
return nil | |||
else | |||
makeerror({message = 'invalid direction', sortkey = 'A'}) | |||
return nil | |||
end | |||
if dmsobject.seconds then -- vérifie la précision des données initiales | |||
precision = 5 + math.max( math_mod._precision(tostring(seconds), 0 ) ) -- passage par des strings assez tarabiscoté ? | |||
elseif dmsobject.minutes then | |||
precision = 3 + math.max( math_mod._precision(tostring(minutes), 0 ) ) | |||
else | |||
precision = math.max( math_mod._precision(tostring(degrees), 0 ) ) | |||
end | |||
local decimal = factor * (degrees+(minutes+seconds/60)/60) | |||
return math_mod._round(decimal, precision) | |||
end | end | ||
--[[ | function p.dms2dec(frame) -- legacy function, somewhat bizarre syntax | ||
local args = frame.args | |||
if tonumber(args[1]) then | |||
return args[1] -- coordonnées déjà en décimal | |||
elseif not args[2] then | |||
return p._dms2dec(parsedmsstring(args[1])) -- coordonnées sous la fore 23/22/N | |||
else | |||
return p._dms2dec({direction = args[1], degrees = args[2], minutes = args[3], seconds = args[4]}) | |||
end | |||
end | end | ||
--[[ | function parsedmsstring(str) -- prend une séquence et donne des noms aux paramètres | ||
-- output table: {latitude=, longitude = , direction = } | |||
if not tonumber(str) and not string.find(str, '/') then | |||
makeerror({message ='invalid coordinate format', sortkey= 'A'}) | |||
return nil | |||
end | |||
args = mw.text.split(str, '/', true) | |||
if #args > 4 then | |||
makeerror({message = "too many parameters for coordinates", sortkey= 'A' }) | |||
end | |||
local direction = args[#args] | |||
table.remove(args) | |||
local degrees, minutes, seconds = args[1], args[2], args[3] | |||
local dimensionobject = builddmsdimension(degrees, minutes, seconds, direction) | |||
if validdms(dimensionobject) then | |||
return dimensionobject | |||
else | |||
return nil | |||
end | |||
end | |||
function builddmsdimension(degrees, minutes, seconds, direction) | |||
-- no error checking, done in function validdms | |||
local dimensionobject = {} | |||
function | |||
-- | |||
-- direction and dimension (= latitude or longitude) | |||
and | dimensionobject.direction = direction | ||
if direction == 'N' or direction == 'S' then | |||
dimensionobject.dimension = 'latitude' | |||
else | |||
dimensionobject.dimension = 'longitude' | |||
end | |||
-- degrees, minutes, seconds | |||
dimensionobject.degrees = tonumber(degrees) | |||
dimensionobject.minutes = tonumber(minutes) | |||
dimensionobject.seconds = tonumber(seconds) | |||
if degrees and not dimensionobject.degrees then dimensionobject.degrees = 'error' end | |||
if minutes and not dimensionobject.minutes then dimensionobject.minutes = 'error' end | |||
if seconds and not dimensionobject.seconds then dimensionobject.seconds = 'error' end | |||
return dimensionobject | |||
end | end | ||
-- | function p.displaydmsdimension(valuetable, format) -- formate en latitude ou une longitude dms | ||
local str = '' | |||
degrees, minutes, | local direction = valuetable.direction | ||
local degrees, minutes, seconds = '', '', '' | |||
local dimension | |||
if format == 'dms long' then | |||
direction = i18n[direction .. 'long'] | |||
else | |||
direction = i18n[direction] | |||
end | |||
degrees = valuetable.degrees .. i18n.degrees | |||
if valuetable.minutes then | |||
minutes = valuetable.minutes .. i18n.minutes | |||
if (valuetable.minutes < 10) then | |||
minutes = '0' .. minutes | |||
end | |||
end | |||
if valuetable.seconds then | |||
seconds = valuetable.seconds .. i18n.seconds | |||
if (valuetable.seconds < 10) then | |||
seconds = '0' .. seconds | |||
end | |||
end | |||
return degrees .. minutes .. seconds .. direction | |||
end | end | ||
function validdms(coordtable) | |||
local direction = coordtable.direction | |||
local degrees = coordtable.degrees or 0 | |||
local minutes = coordtable.minutes or 0 | |||
local seconds = coordtable.seconds or 0 | |||
local dimension = coordtable.dimension | |||
if type(degrees) ~= 'number' or type(minutes) ~= 'number' or type(seconds) ~= 'number' then | |||
makeerror({message = 'coordinates should be numeric', sortkey = 'A'}) | |||
return false | |||
end | |||
if dimension == 'latitude' and direction ~= 'N' and direction ~= 'S' then | |||
makeerror({message = 'could not find latitude direction (should be N or S)', sortkey = 'A'}) | |||
return false | |||
end | |||
if dimension == 'longitude' and direction ~= 'W' and direction ~= 'E' then | |||
makeerror({message = 'could not find longitude direction (should be W or E) ', sortkey = 'A'}) | |||
return false | |||
end | |||
if dimension == 'latitude' and degrees > 90 then | |||
makeerror({'latitude > 90', sortkey = 'A'}) | |||
return false | |||
end | |||
if dimension == 'longitude' and degrees > 180 then | |||
makeerror({'longitude > 180', sortkey = 'A'}) | |||
return false | |||
end | |||
if degrees < 0 or minutes < 0 or seconds < 0 then | |||
makeerror({message = 'dms coordinates should be positive', sortkey = 'A'}) | |||
return false | |||
end | |||
if (math.floor(degrees) ~= degrees and minutes ~= 0) or (math.floor(minutes) ~= minutes and seconds ~= 0) then | |||
makeerror({message = 'degrees and minutes should be integers', sortkey = 'A'}) | |||
return false | |||
end | |||
return true | |||
end | end | ||
-- | function validlatitude(value) -- decimal latitude | ||
if type(value) ~= 'number' or math.abs(value) > 90 then | |||
makeerror({message = 'latitude should be number < 90, is ' .. (value or 'nil')}) | |||
return false | |||
end | |||
return true | |||
end | end | ||
-- | function validlongitude(value) -- decimal longitude | ||
if type(value) ~= 'number' or math.abs(value) > 180 then | |||
makeerror({message = 'longitude should be number < 180, is ' .. (value or 'nil')}) | |||
return false | |||
end | |||
return true | |||
end | |||
function p.displaydec(latitude, longitude, format) | |||
if format == 'dec west' then | |||
local latsymbol = i18n.N | |||
longitude = - longitude | |||
if latitude < 0 then latsymbol = i18n.S end | |||
if longitude < 0 then | |||
long = 360 + longitude | |||
end | |||
return latitude .. i18n.degrees .. latsymbol .. ', ' .. longitude .. i18n.degrees .. i18n.W | |||
elseif format == 'dec west' then | |||
local latsymbol = i18n.N | |||
if latitude < 0 then latsymbol = i18n.S end | |||
if longitude < 0 then | |||
longitude = 360 + longitude | |||
end | |||
return latitude .. i18n.degrees .. latsymbol .. ', ' .. longitude .. i18n.degrees .. i18n.E | |||
else | |||
return latitude .. ', ' .. longitude | |||
end | |||
end | end | ||
function wikidatacoords(query) | |||
query = query or {property = 'p625'} | |||
local wd = require('Module:Wikidata') | |||
function | local claim = wd.getClaims(query) | ||
if claim and claim[1] then -- redundant but more robust in case of a change in the code of Module:Wikidata | |||
local coords = wd.formatSnak(claim[1].mainsnak) -- todo: check for special values | |||
return coords.latitude, coords.longitude, coords.globe | |||
end | |||
return nil | |||
end | end | ||
-- | --- fonctions principales | ||
function p._coord(args) | |||
local latitude, longitude = tonumber(args.latitude), tonumber(args.longitude) -- must be in decimal format | |||
if latitude and longitude and (not validlatitude(latitude) or not validlongitude(longitude)) then | |||
return showerrors() | |||
end | |||
local displayformat, inputformat = args.format, args.inputformat -- one of: 'dms', 'dms long', 'dec', 'dec east' and 'dec west' | |||
local displayplace = string.lower(args.display or 'inline') -- on of 'inline', 'title' or 'inline,title' | |||
local globe = string.lower(args.globe or '') -- planet see the globedata table for accepted values | |||
local objectname = args.name -- name of the title displayed in geohack | |||
local notes = (' ' and args.notes) or '' -- notes à afficher après les coordonnées | |||
local wikidata = args.wikidata -- string set to true when | |||
local dmslatitude, dmslongitude -- type: table when created | |||
local extraparams = string.lower(args.extraparams or '') -- chaîne destinée à geohack dernier paramètre avec argument numérique dans {{Coord}} | |||
local wikidataquery = args.wikidataquery | |||
local trackingstring = '' -- tracking cats except error cats (already in errorstring) | |||
-- parsage des donnés en format non-décimal | |||
if (not latitude and args.latitude and args.latitude ~= '') then -- latitude was not a number | |||
dmslatitude = parsedmsstring(args.latitude) | |||
if not dmslatitude then return showerrors() end | |||
latitude = p._dms2dec(dmslatitude) | |||
end | |||
if (not longitude and args.longitude and args.longitude ~= '') then -- latitude was not a number | |||
dmslongitude = parsedmsstring(args.longitude) | |||
if not dmslongitude then return showerrors() end | |||
longitude = p._dms2dec(dmslongitude) | |||
end | |||
-- récuparation des coordonnées Wikidata | |||
local wikidatalatitude, wikidatalongitude, wikidataglobe | |||
if wikidata == 'true' then | |||
wikidatalatitude, wikidatalongitude, wikidataglobe = wikidatacoords(wikidataquery) | |||
end | |||
if wikidatalatitude and latitude then | |||
local maxdistance = tonumber(args.maxdistance) or wikidatathreshold | |||
if p._distance({latitude = latitude, longitude= longitude}, {latitude = wikidatalatitude, longitude= wikidatalongitude}, wikidataglobe) < maxdistance then | |||
trackingstring = trackingstring .. makecat(i18n.sameaswikidata) | |||
else | |||
trackingstring = trackingstring .. makecat(i18n.notaswikidata) | |||
end | |||
end | |||
if wikidatalatitude and not latitude then | |||
latitude, longitude, globe = wikidatalatitude, wikidatalongitude, wikidataglobe | |||
trackingstring = trackingstring .. makecat(i18n.throughwikidata) | |||
end | |||
-- exit if stil no latitude or not longitude | |||
if not latitude and not longitude then | |||
return nil -- ne rien ajouter ici pour que l'appel à cette fonction retourne bien nil en l'absence de données | |||
end | |||
if not latitude or not longitude then | |||
makeerror({message = 'latitude or longitude missing', sortkey = 'A'}) | |||
return showerrors() | |||
end | |||
-- best guesses for missing parameters | |||
--- globe | |||
if globe == '' then -- cherche le globe dans l'extraparams destinée à geohack | |||
local globe2 = string.match(extraparams, 'globe\:%a+') | |||
if globe2 then globe = string.sub(globe2, 7) end | |||
end | |||
if globe == '' then | |||
globe = 'earth' | |||
end | |||
if not globedata[globe] then | |||
makeerror({message = 'invalid globe:' .. globe}) | |||
globe = 'earth' | |||
end | |||
--- diplayformat | |||
if not displayformat or displayformat == '' then | |||
if dmslatitude then -- keeps the same format for output as for input, but dms by default when coordinates come from Wikidata | |||
displayformat = 'dms' | |||
else | |||
displayformat = 'dec' | |||
end | |||
end | |||
-- displayinline/displaytitle | |||
local displayinline = string.find(displayplace, 'inline') | |||
local displaytitle = string.find(displayplace, 'title') | |||
if not displayinline and not displaytitle then | |||
displayinline = true | |||
if displayplace ~= '' then | |||
makeerror({sortkey = 'C'}) --error if display not empty, but not not a major error, continue | |||
end | |||
end | end | ||
if | if displaytitle and mw.title.getCurrentTitle().namespace == 0 then | ||
trackingstring = trackingstring .. makecat(globedata[globe].trackingcat) | |||
end | end | ||
-- standardize format for astronomical objects so that it can be used by geohack (back converted afterwards, pretty fast) | |||
end | if inputformat == 'dec east' then | ||
if longitude > 180 then | |||
longitude = longitude - 360 | |||
end | |||
longitude = - longitude | |||
end | |||
if inputformat == 'dec west' then | |||
if longitude > 180 then | |||
longitude = longitude - 360 | |||
end | |||
end | |||
-- | -- finish up | ||
if not dmslatitude then | |||
dmslatitude, dmslongitude = p._dec2dms(latitude, 'latitude'), p._dec2dms(longitude, 'longitude') | |||
end | |||
extraparams = extraparams .. '_globe:' .. globe -- pas de problème si le globe est en double | |||
-- final output | |||
local mainstring = '' | |||
mainstring = buildHTML(latitude, longitude, dmslatitude, dmslongitude, globe, displayformat, displayinline, displaytitle, objectname,extraparams ) | |||
return mainstring .. notes .. trackingstring .. showerrors() | |||
end | end | ||
-- | function p.coord(frame) -- parrses the strange parameters of Template:Coord before sending them to p.coord | ||
local args = frame.args | |||
local numericargs = {} | |||
for i, j in ipairs(args) do | |||
args[i] = mw.text.trim(j) | |||
if type(i) == 'number' and args[i] ~= '' then | |||
table.insert(numericargs, args[i]) | |||
end | |||
end | |||
end | |||
if #numericargs == 1 then | |||
makeerror({message = 'invalid coordinates format', sortkey = 'A'}) | |||
return showerrors() | |||
elseif #numericargs %2 == 1 then -- if the number of args is odd, the last one provides formatting parameters | |||
args.extraparams = numericargs[#numericargs] | |||
table.remove(numericargs) | |||
end | |||
for i, j in ipairs(numericargs) do | |||
if i <= (#numericargs / 2) then | |||
if not args.latitude then | |||
args.latitude = j | |||
else | |||
args.latitude = args.latitude .. '/' .. j | |||
end | |||
else | |||
if not args.longitude then | |||
args.longitude = j | |||
else | |||
args.longitude = args.longitude .. '/' .. j | |||
end | |||
end | |||
end | |||
if string.find(args.latitude or '', 'E') or string.find(args.latitude or '', 'W') then | |||
args.latitude, args.longitude = args.longitude, args.latitude | |||
end | |||
if args.formatitle then -- legacy parameter | |||
args.display = 'inline' | |||
local inline = p._coord(args) | |||
args.display = 'title' | |||
args.format = args.formatitle | |||
local title = p._coord(args) | |||
return (inline or '') .. (title or '') | |||
else | |||
return p._coord(args) | |||
end | |||
end | end | ||
function p.Coord(frame) | |||
return p.coord(frame) | |||
function | |||
end | end | ||
function | function p.latitude(frame) -- helper function for infoboxes, à déprécier | ||
if frame.args[1] and frame.args[1] ~= ''then | if frame.args[1] and frame.args[1] ~= '' then | ||
return frame.args[1] | return frame.args[1] | ||
else | |||
return wikidatacoords( | return wikidatacoords(frame.args.query) | ||
end | end | ||
end | end | ||
return p | |||
Version du 18 février 2014 à 22:05
La documentation pour ce module peut être créée à Module:Coordinates/doc
local math_mod = require( "Module:Math" )
local p = {}
local i18n = {
N = ' N',
Nlong = ' Nord',
W = ' O',
Wlong = ' Ouest',
E = ' E',
Elong = ' Est',
S = ' S',
Slong = ' Sud',
degrees = '° ',
minutes = '\′ ',
seconds = '″ ',
geohackurl = 'http://tools.wmflabs.org/geohack/geohack.php?language=fr',
tooltip = 'Cartes, vues aériennes et autres données pour cet endroit',
errorcat = 'Pages avec des balises de coordonnées mal formées',
sameaswikidata = 'Page avec coordonnées similaires sur Wikidata',
notaswikidata = 'Page avec coordonnées différentes sur Wikidata',
throughwikidata = 'Page géolocalisée par Wikidata',
}
local globedata = {
--[[ notes:
radius in kilometers (especially imprecise for non spheric bodies)
defaultdisplay is currently disabled, activate it ?
]]--
ariel = {radius = 580, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
callisto = {radius = 2410, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
ceres = {radius = 470, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
deimos = {radius = 7, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
dione = {radius = 560, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
enceladus = {radius = 255, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
ganymede = {radius = 1631, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
earth = {radius = 6371, defaultdisplay = 'dms', trackingcat = 'Article géolocalisé sur Terre'},
europe = {radius = 1561, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
hyperion = {radius = 140, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
iapetus = {radius = 725, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
['io'] = {radius = 1322, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
jupiter = {radius = 68911, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
mars = {radius = 3389.5, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé sur Mars' },
mercury = {radius = 2439.7, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
mimas = {radius = 197, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
miranda = {radius = 335, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
moon = {radius = 1736, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé sur la Lune'},
neptune = {radius = 24553, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
oberon = {radius = 761, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
phoebe = {radius = 110, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
phobos = {radius = 11, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
rhea = {radius = 765, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
saturn = {radius = 58232, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
titan = {radius = 2575.5, defaultdisplay = 'dec west', trackingcat = 'Article géolocalisé extraterrestre'},
tethys = {radius = 530, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
titania = {radius = 394, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
triton = {radius = 1353, defaultdisplay = 'dec west', trackingcat = 'Article géolocalisé extraterrestre'},
umbriel = {radius = 584, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
uranus = {radius = 25266, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
venus = {radius = 6051.8, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'},
vesta = {radius = 260, defaultdisplay = 'dec east', trackingcat = 'Article géolocalisé extraterrestre'}
}
local wikidatathreshold = 10 -- si la distance entre coordonnées Wikipédia et Wikidata dépasse se seuil (en kilomètes), une catégorie de maintenance est ajoutée
----------------------------------------
--Error handling
--[[ Notes:
when errors occure a new error message is concatenated to errorstring
an error message contains an error category with a sortkey
For major errors, it can also display an error message (the error message will the usually be returned and the function terminated)
More minor errors do only add a category, so that readers are not bothered with error texts
sortkeys:
* A: invalid latitude, longitude or direction
* B: invalid globe
* C: something wrong with other parameters
]]--
errorstring = ''
function makeerror(args)
local errormessage = ''
if args.message then
errormessage = '<strong class="error">Coordonnées: ' .. args.message .. '</strong>'
end
local errorcat = ''
if mw.title.getCurrentTitle().namespace == 0 then
errorcat = makecat(i18n.errorcat, args.sortkey)
end
errorstring = errormessage .. errorcat -- reinitializes the string to avoid absurdly long messages
return nil
end
function showerrors()
return errorstring
end
-------------------------------------------
function makecat(cat, sortkey)
return '[[Category:' .. cat .. '|' .. (sortkey or '*') .. ']]'
end
----------------------------------------
-- Distance computation
function p._distance(a, b, globe) -- calcule la [[distance orthodromique]] en kilomètres entre deux points du globe
globe = string.lower(globe or 'earth')
-- check arguments and converts degreees to radians
local latA, latB, longA, longB = a.latitude, b.latitude, a.longitude, b.longitude
if not latA or not latB or not longA or not longB then return
error('coordinates missing, can\'t compute distance')
end
if type(latA) ~= 'number' or type(latB) ~= 'number' or type(longA) ~= 'number' or type(longB) ~= 'number' then
error('coordinates are not numeric, can\'t compute distance')
end
-- distance angulaire en radians
local convratio = math.pi / 180 -- convertit en radians
latA, latB, longA, longB = convratio * latA, convratio * latB, convratio * longA, convratio * longB
local angle = math.acos(math.sin(latA) * math.sin(latB) + math.cos(latA) * math.cos(latB) * math.cos(longB - longA))
-- convertit en km en fonction du globe
if not globe or not globedata[globe] then
return error('globe: ' .. globe .. 'is not supported')
end
radius = globedata[globe].radius
return radius * angle
end
function p.distance(frame)
local args = frame.args
return p._distance(
{latitude = tonumber(args.latitude1), longitude = tonumber(args.longitude1)},
{latitude = tonumber(args.latitude2), longitude = tonumber(args.longitude2)},
args.globe)
end
------------------------
--HTML builder for a geohack link
local function buildHTML(decLat, decLong, dmsLat, dmsLong, globe, displayformat, displayinline, displaytitle, objectname, extraparams)
local htmlBuilder = require("Module:HtmlBuilder")
local root, text, url, noprint
extraparams = extraparams or ''
-- geohack url and parameters
local decimalcoords = p.displaydec(decLat, decLong, displayformat)
local geohacklatitude, geohacklongitude
-- format latitude and longitude for the URL
if tonumber(decLat) < 0 then
geohacklatitude = tostring(-tonumber(decLat)) .. '_S'
else
geohacklatitude = decLat .. '_N'
end
if tonumber(decLong) < 0 then
geohacklongitude = tostring(-tonumber(decLong)) .. '_W'
else
geohacklongitude = decLong .. '_E'
end
-- prepares the 'paramss=' parameter
local geohackparams = geohacklatitude .. '_' .. geohacklongitude .. '_' ..extraparams
-- concatenate parameteres for geohack
local url = i18n.geohackurl ..
"&pagename=" .. mw.uri.encode(mw.title.getCurrentTitle().prefixedText, "WIKI") ..
"¶ms=" .. geohackparams ..
(objectname and ("&title=" .. mw.uri.encode(objectname)) or "")
root = htmlBuilder.create()
root
.tag("span")
.addClass("plainlinks nourlexpansion")
.wikitext("[" .. url)
.tag("span")
.addClass(string.sub(displayformat,1,3) == "dec" and "geo-nondefault" or "geo-default")
.tag("span")
.addClass("geo-dms")
.attr("title", i18n.tooltip)
.tag("span")
.addClass("latitude")
.wikitext(p.displaydmsdimension(dmsLat, displayformat))
.done()
.wikitext(" ")
.tag("span")
.addClass("longitude")
.wikitext(p.displaydmsdimension(dmsLong, displayformat))
.done()
.done()
.done()
.tag("span")
.addClass("geo-multi-punct")
.wikitext(" / ")
.done()
.tag("span")
.addClass(string.sub(displayformat,1,3) == 'dec' and "geo-default" or "geo-nondefault")
.wikitext(objectname and "<span class=\"vcard\">" or "")
.tag("span")
.addClass("geo-dec")
.attr("title", i18n.tooltip)
.wikitext(decimalcoords)
.done()
.wikitext(objectname and ("<span style=\"display:none\"> (<span class=\"fn org\">" ..
objectname .. "</span>)</span></span>") or "")
.done()
.wikitext("]")
.done()
-- formatta il risultato a seconda di args["display"] (nil, "inline", "title", "inline,title")
text = tostring(root)
noprint = displayinline and "class=\"noprint\" " or ""
htmlTitle = "<span style=\"font-size: small;\"><span " .. noprint .. "id=\"coordinates\">"
return (displayinline and text or "") ..
(displaytitle and (htmlTitle .. text .. "</span></span>") or "")
end
-- Fonctions de manipualation/coonversion des coordonnées
function p._dec2dms(dec, coordtype, precision) -- type: latitude or longitude
local dec = tonumber(dec)
local dms = {}
-- precision
if precision and precision ~= '' and precision ~= 'd' and precision ~= 'dm' and precision ~= 'dms' then
return makeerror({sortkey = 'C'})
end
if not precision then
precision = math_mod._precision(dec)
if precision <= 0 then
precision = 'd'
elseif precision <= 2 then
precision = 'dm';
else
precision = 'dms';
end
end -- et fractions de secondes ?
if precision ~= 'd' and precision ~= 'dm' and precision ~= 'dms' then
makeerror({message = 'invalid precision in function dec2dms', sortkey = 'C'})
end
-- direction
if coordtype == 'latitude' then
if dec < 0 then
direction = 'S'
else
direction = 'N'
end
elseif coordtype == 'longitude' then
if dec < 0 then
direction = 'W'
else
direction = 'E'
end
end
-- conversion
dec = math.abs(dec) -- les coordonnées en dms sont toujours positives
if precision == 'dms' then
dec = math_mod._round( dec * 60 * 60, 0 )
seconds = dec % 60
dec = (dec - seconds) / 60 / 60
end
if precision == 'dm' or precision == 'dms' then
dec = math_mod._round( dec * 60, 0 )
minutes = dec % 60
dec = (dec - minutes) / 60
end
degrees = math_mod._round(dec, 0)
return builddmsdimension(degrees, minutes, seconds, direction)
end
function p.dec2dms(frame) -- legacy function somewhat cumbersome syntax
args = frame.args
local dec = args[1]
local precision = string.lower(args[4])
local displayformat, coordtype
if args[2] == 'N' or 'Nord' then
coordtype = 'latitude'
else
coordtype = 'longitude'
end
if args[2] == 'Nord' or args[2] == 'Est' or args[2] == 'Ouest' then
displayformat = 'dms long'
end
local coordobject = p._dec2dms(dec, coordtype, precision)
return p.displaydmsdimension(coordobject, displayformat) .. showerrors()
end
function p._dms2dec(dmsobject) -- transforme une table degré minute secondes en nombre décimal
local direction, degrees, minutes, seconds = dmsobject.direction, dmsobject.degrees, dmsobject.minutes, dmsobject.seconds
local factor = 0
local precision = 0
if not minutes then minutes = 0 end
if not seconds then seconds = 0 end
if direction == "N" or direction == "E" then
factor = 1
elseif direction == "W" or direction == "S" then
factor = -1
elseif not direction then
makeerror({message = 'no cardinal direction found in coordinates', sortkey = 'A'})
return nil
else
makeerror({message = 'invalid direction', sortkey = 'A'})
return nil
end
if dmsobject.seconds then -- vérifie la précision des données initiales
precision = 5 + math.max( math_mod._precision(tostring(seconds), 0 ) ) -- passage par des strings assez tarabiscoté ?
elseif dmsobject.minutes then
precision = 3 + math.max( math_mod._precision(tostring(minutes), 0 ) )
else
precision = math.max( math_mod._precision(tostring(degrees), 0 ) )
end
local decimal = factor * (degrees+(minutes+seconds/60)/60)
return math_mod._round(decimal, precision)
end
function p.dms2dec(frame) -- legacy function, somewhat bizarre syntax
local args = frame.args
if tonumber(args[1]) then
return args[1] -- coordonnées déjà en décimal
elseif not args[2] then
return p._dms2dec(parsedmsstring(args[1])) -- coordonnées sous la fore 23/22/N
else
return p._dms2dec({direction = args[1], degrees = args[2], minutes = args[3], seconds = args[4]})
end
end
function parsedmsstring(str) -- prend une séquence et donne des noms aux paramètres
-- output table: {latitude=, longitude = , direction = }
if not tonumber(str) and not string.find(str, '/') then
makeerror({message ='invalid coordinate format', sortkey= 'A'})
return nil
end
args = mw.text.split(str, '/', true)
if #args > 4 then
makeerror({message = "too many parameters for coordinates", sortkey= 'A' })
end
local direction = args[#args]
table.remove(args)
local degrees, minutes, seconds = args[1], args[2], args[3]
local dimensionobject = builddmsdimension(degrees, minutes, seconds, direction)
if validdms(dimensionobject) then
return dimensionobject
else
return nil
end
end
function builddmsdimension(degrees, minutes, seconds, direction)
-- no error checking, done in function validdms
local dimensionobject = {}
-- direction and dimension (= latitude or longitude)
dimensionobject.direction = direction
if direction == 'N' or direction == 'S' then
dimensionobject.dimension = 'latitude'
else
dimensionobject.dimension = 'longitude'
end
-- degrees, minutes, seconds
dimensionobject.degrees = tonumber(degrees)
dimensionobject.minutes = tonumber(minutes)
dimensionobject.seconds = tonumber(seconds)
if degrees and not dimensionobject.degrees then dimensionobject.degrees = 'error' end
if minutes and not dimensionobject.minutes then dimensionobject.minutes = 'error' end
if seconds and not dimensionobject.seconds then dimensionobject.seconds = 'error' end
return dimensionobject
end
function p.displaydmsdimension(valuetable, format) -- formate en latitude ou une longitude dms
local str = ''
local direction = valuetable.direction
local degrees, minutes, seconds = '', '', ''
local dimension
if format == 'dms long' then
direction = i18n[direction .. 'long']
else
direction = i18n[direction]
end
degrees = valuetable.degrees .. i18n.degrees
if valuetable.minutes then
minutes = valuetable.minutes .. i18n.minutes
if (valuetable.minutes < 10) then
minutes = '0' .. minutes
end
end
if valuetable.seconds then
seconds = valuetable.seconds .. i18n.seconds
if (valuetable.seconds < 10) then
seconds = '0' .. seconds
end
end
return degrees .. minutes .. seconds .. direction
end
function validdms(coordtable)
local direction = coordtable.direction
local degrees = coordtable.degrees or 0
local minutes = coordtable.minutes or 0
local seconds = coordtable.seconds or 0
local dimension = coordtable.dimension
if type(degrees) ~= 'number' or type(minutes) ~= 'number' or type(seconds) ~= 'number' then
makeerror({message = 'coordinates should be numeric', sortkey = 'A'})
return false
end
if dimension == 'latitude' and direction ~= 'N' and direction ~= 'S' then
makeerror({message = 'could not find latitude direction (should be N or S)', sortkey = 'A'})
return false
end
if dimension == 'longitude' and direction ~= 'W' and direction ~= 'E' then
makeerror({message = 'could not find longitude direction (should be W or E) ', sortkey = 'A'})
return false
end
if dimension == 'latitude' and degrees > 90 then
makeerror({'latitude > 90', sortkey = 'A'})
return false
end
if dimension == 'longitude' and degrees > 180 then
makeerror({'longitude > 180', sortkey = 'A'})
return false
end
if degrees < 0 or minutes < 0 or seconds < 0 then
makeerror({message = 'dms coordinates should be positive', sortkey = 'A'})
return false
end
if (math.floor(degrees) ~= degrees and minutes ~= 0) or (math.floor(minutes) ~= minutes and seconds ~= 0) then
makeerror({message = 'degrees and minutes should be integers', sortkey = 'A'})
return false
end
return true
end
function validlatitude(value) -- decimal latitude
if type(value) ~= 'number' or math.abs(value) > 90 then
makeerror({message = 'latitude should be number < 90, is ' .. (value or 'nil')})
return false
end
return true
end
function validlongitude(value) -- decimal longitude
if type(value) ~= 'number' or math.abs(value) > 180 then
makeerror({message = 'longitude should be number < 180, is ' .. (value or 'nil')})
return false
end
return true
end
function p.displaydec(latitude, longitude, format)
if format == 'dec west' then
local latsymbol = i18n.N
longitude = - longitude
if latitude < 0 then latsymbol = i18n.S end
if longitude < 0 then
long = 360 + longitude
end
return latitude .. i18n.degrees .. latsymbol .. ', ' .. longitude .. i18n.degrees .. i18n.W
elseif format == 'dec west' then
local latsymbol = i18n.N
if latitude < 0 then latsymbol = i18n.S end
if longitude < 0 then
longitude = 360 + longitude
end
return latitude .. i18n.degrees .. latsymbol .. ', ' .. longitude .. i18n.degrees .. i18n.E
else
return latitude .. ', ' .. longitude
end
end
function wikidatacoords(query)
query = query or {property = 'p625'}
local wd = require('Module:Wikidata')
local claim = wd.getClaims(query)
if claim and claim[1] then -- redundant but more robust in case of a change in the code of Module:Wikidata
local coords = wd.formatSnak(claim[1].mainsnak) -- todo: check for special values
return coords.latitude, coords.longitude, coords.globe
end
return nil
end
--- fonctions principales
function p._coord(args)
local latitude, longitude = tonumber(args.latitude), tonumber(args.longitude) -- must be in decimal format
if latitude and longitude and (not validlatitude(latitude) or not validlongitude(longitude)) then
return showerrors()
end
local displayformat, inputformat = args.format, args.inputformat -- one of: 'dms', 'dms long', 'dec', 'dec east' and 'dec west'
local displayplace = string.lower(args.display or 'inline') -- on of 'inline', 'title' or 'inline,title'
local globe = string.lower(args.globe or '') -- planet see the globedata table for accepted values
local objectname = args.name -- name of the title displayed in geohack
local notes = (' ' and args.notes) or '' -- notes à afficher après les coordonnées
local wikidata = args.wikidata -- string set to true when
local dmslatitude, dmslongitude -- type: table when created
local extraparams = string.lower(args.extraparams or '') -- chaîne destinée à geohack dernier paramètre avec argument numérique dans {{Coord}}
local wikidataquery = args.wikidataquery
local trackingstring = '' -- tracking cats except error cats (already in errorstring)
-- parsage des donnés en format non-décimal
if (not latitude and args.latitude and args.latitude ~= '') then -- latitude was not a number
dmslatitude = parsedmsstring(args.latitude)
if not dmslatitude then return showerrors() end
latitude = p._dms2dec(dmslatitude)
end
if (not longitude and args.longitude and args.longitude ~= '') then -- latitude was not a number
dmslongitude = parsedmsstring(args.longitude)
if not dmslongitude then return showerrors() end
longitude = p._dms2dec(dmslongitude)
end
-- récuparation des coordonnées Wikidata
local wikidatalatitude, wikidatalongitude, wikidataglobe
if wikidata == 'true' then
wikidatalatitude, wikidatalongitude, wikidataglobe = wikidatacoords(wikidataquery)
end
if wikidatalatitude and latitude then
local maxdistance = tonumber(args.maxdistance) or wikidatathreshold
if p._distance({latitude = latitude, longitude= longitude}, {latitude = wikidatalatitude, longitude= wikidatalongitude}, wikidataglobe) < maxdistance then
trackingstring = trackingstring .. makecat(i18n.sameaswikidata)
else
trackingstring = trackingstring .. makecat(i18n.notaswikidata)
end
end
if wikidatalatitude and not latitude then
latitude, longitude, globe = wikidatalatitude, wikidatalongitude, wikidataglobe
trackingstring = trackingstring .. makecat(i18n.throughwikidata)
end
-- exit if stil no latitude or not longitude
if not latitude and not longitude then
return nil -- ne rien ajouter ici pour que l'appel à cette fonction retourne bien nil en l'absence de données
end
if not latitude or not longitude then
makeerror({message = 'latitude or longitude missing', sortkey = 'A'})
return showerrors()
end
-- best guesses for missing parameters
--- globe
if globe == '' then -- cherche le globe dans l'extraparams destinée à geohack
local globe2 = string.match(extraparams, 'globe\:%a+')
if globe2 then globe = string.sub(globe2, 7) end
end
if globe == '' then
globe = 'earth'
end
if not globedata[globe] then
makeerror({message = 'invalid globe:' .. globe})
globe = 'earth'
end
--- diplayformat
if not displayformat or displayformat == '' then
if dmslatitude then -- keeps the same format for output as for input, but dms by default when coordinates come from Wikidata
displayformat = 'dms'
else
displayformat = 'dec'
end
end
-- displayinline/displaytitle
local displayinline = string.find(displayplace, 'inline')
local displaytitle = string.find(displayplace, 'title')
if not displayinline and not displaytitle then
displayinline = true
if displayplace ~= '' then
makeerror({sortkey = 'C'}) --error if display not empty, but not not a major error, continue
end
end
if displaytitle and mw.title.getCurrentTitle().namespace == 0 then
trackingstring = trackingstring .. makecat(globedata[globe].trackingcat)
end
-- standardize format for astronomical objects so that it can be used by geohack (back converted afterwards, pretty fast)
if inputformat == 'dec east' then
if longitude > 180 then
longitude = longitude - 360
end
longitude = - longitude
end
if inputformat == 'dec west' then
if longitude > 180 then
longitude = longitude - 360
end
end
-- finish up
if not dmslatitude then
dmslatitude, dmslongitude = p._dec2dms(latitude, 'latitude'), p._dec2dms(longitude, 'longitude')
end
extraparams = extraparams .. '_globe:' .. globe -- pas de problème si le globe est en double
-- final output
local mainstring = ''
mainstring = buildHTML(latitude, longitude, dmslatitude, dmslongitude, globe, displayformat, displayinline, displaytitle, objectname,extraparams )
return mainstring .. notes .. trackingstring .. showerrors()
end
function p.coord(frame) -- parrses the strange parameters of Template:Coord before sending them to p.coord
local args = frame.args
local numericargs = {}
for i, j in ipairs(args) do
args[i] = mw.text.trim(j)
if type(i) == 'number' and args[i] ~= '' then
table.insert(numericargs, args[i])
end
end
if #numericargs == 1 then
makeerror({message = 'invalid coordinates format', sortkey = 'A'})
return showerrors()
elseif #numericargs %2 == 1 then -- if the number of args is odd, the last one provides formatting parameters
args.extraparams = numericargs[#numericargs]
table.remove(numericargs)
end
for i, j in ipairs(numericargs) do
if i <= (#numericargs / 2) then
if not args.latitude then
args.latitude = j
else
args.latitude = args.latitude .. '/' .. j
end
else
if not args.longitude then
args.longitude = j
else
args.longitude = args.longitude .. '/' .. j
end
end
end
if string.find(args.latitude or '', 'E') or string.find(args.latitude or '', 'W') then
args.latitude, args.longitude = args.longitude, args.latitude
end
if args.formatitle then -- legacy parameter
args.display = 'inline'
local inline = p._coord(args)
args.display = 'title'
args.format = args.formatitle
local title = p._coord(args)
return (inline or '') .. (title or '')
else
return p._coord(args)
end
end
function p.Coord(frame)
return p.coord(frame)
end
function p.latitude(frame) -- helper function for infoboxes, à déprécier
if frame.args[1] and frame.args[1] ~= '' then
return frame.args[1]
else
return wikidatacoords(frame.args.query)
end
end
return p