imported>Jacques Ducloy |
imported>Jacques Ducloy |
Ligne 1 : |
Ligne 1 : |
− | local math_mod = require( "Module:Math" )
| + | --[[ |
| | | |
− | local p = {}
| + | This module provides a number of basic mathematical operations. |
| | | |
− | --Chargement de la liste En/Au/Aux/A
| + | ]] |
− | local gdata
| + | local z = {} |
− | local success, resultat = pcall (mw.loadData, "Module:Drapeau/Data" )
| |
− | if success then
| |
− | gdata = resultat
| |
− | else
| |
− | -- Banque de données à minima en cas de bogue dans le Module:Langue/Data
| |
− | gdata={}
| |
− | gdata.data={};
| |
− | gdata.data[142]={qid="Q142", label="France", genre="fs"}
| |
− | end
| |
− | | |
− | 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, etc.',
| |
− | errorcat = 'Page 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',
| |
− | nowikidata = 'Page sans coordonnées Wikidata',
| |
− | throughwikidata = 'Page géolocalisée par Wikidata',
| |
− | invalidFormat = 'format invalide', -- 'invalid coordinate format',
| |
− | invalidNSEW = 'orientation invalide, devrait être "N", "S", "E" or "W"', -- 'invalid direction should be "N", "S", "E" or "W"',
| |
− | invalidNS = 'orientation de latitude invalide, devrait être "N" ou "S"', -- 'could not find latitude direction (should be N or S)',
| |
− | invalidEW = 'orientation de longitude invalide, devrait être "E" ou "W"', -- 'could not find longitude direction (should be W or E) ',
| |
− | noCardinalDirection = 'orientation cardinale non trouvée', -- 'no cardinal direction found in coordinates',
| |
− | invalidDirection = 'direction invalide', -- 'invalid direction',
| |
− | latitude90 = 'latitude > 90',
| |
− | longitude360 = 'longitude > 360',
| |
− | minSec60 = 'minutes ou secondes > 60',
| |
− | negativeCoode = 'en format dms les degrés doivent être positifs', -- 'dms coordinates should be positive',
| |
− | dmIntergers = 'degrés et minutes doivent être des nombres entiers', -- 'degrees and minutes should be integers',
| |
− | tooManyParam = 'trop de paramètres pour la latitude ou la longitude', -- 'too many parameters for coordinates',
| |
− | coordMissing = 'latitude ou longitude absente', -- 'latitude or longitude missing',
| |
− | invalidGlobe = 'globe invalide : ', -- 'invalid globe:',
| |
− | }
| |
− | local coordParse = {
| |
− | NORTH = 'N',
| |
− | NORD = 'N',
| |
− | EAST = 'E',
| |
− | EST = 'E',
| |
− | WEST = 'W',
| |
− | O = 'W',
| |
− | OUEST = 'W',
| |
− | SOUTH = 'S',
| |
− | SUD = 'S',
| |
− | }
| |
− | | |
− | --Aide:Fonction_genre
| |
− | local genre = {
| |
− | ms = {le="le ", du="du ", de="du ", au="au ", en="au "},
| |
− | msa = {le="l'", du="de l'", de="d'", au="à l'", en="en "},
| |
− | msi = {le="", du="de ", de="de ", au="à ", en="à "},
| |
− | msia = {le="", du="d'", de="d'", au="à ", en="à "},
| |
− | msiae = {le="", du="d'", de="d'", au="à ", en="en "},
| |
− | fs = {le="la ", du="de la ", de="de ", au="à la ",en="en "},
| |
− | fsa = {le="l'", du="de l'", de="d'", au="à l'", en="en "},
| |
− | fsi = {le="", du="de ", de="de ", au="à ", en="à "},
| |
− | fsia = {le="", du="d'", de="d'", au="à ", en="à "},
| |
− | mp = {le="les ", du="des ", de="des ", au="aux ", en="aux "},
| |
− | fp = {le="les ", du="des ", de="des ", au="aux ", en="aux "}
| |
− | } | |
| | | |
− | local globedata = {
| + | -- Generate random number |
− | --[[ notes:
| + | function z.random( frame ) |
− | radius in kilometers (especially imprecise for non spheric bodies)
| + | local first = tonumber(frame.args[1]) -- if it doesn't exist it's NaN, if not a number it's nil |
− | defaultdisplay is currently disabled, activate it ?
| + | local second = tonumber(frame.args[2]) |
− | ]]--
| |
− | ariel = {radius = 580, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
| |
− | callisto = {radius = 2410, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
| |
− | ceres = {radius = 470, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
| |
− | charon = {radius = 1214, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
| |
− | deimos = {radius = 7, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
| |
− | dione = {radius = 560, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
| |
− | enceladus = {radius = 255, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
| |
− | ganymede = {radius = 2634, defaultdisplay = 'dec west', trackingcat = 'sur Ganymède'},
| |
− | earth = {radius = 6371, defaultdisplay = 'dms', trackingcat = 'sur Terre'},
| |
− | europa = {radius = 1561, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
| |
− | hyperion = {radius = 140, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
| |
− | iapetus = {radius = 725, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
| |
− | ['io'] = {radius = 1322, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
| |
− | jupiter = {radius = 68911, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
| |
− | mars = {radius = 3389.5, defaultdisplay = 'dec east', trackingcat = 'sur Mars' },
| |
− | mercury = {radius = 2439.7, defaultdisplay = 'dec west', trackingcat = 'sur Mercure'},
| |
− | mimas = {radius = 197, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
| |
− | miranda = {radius = 335, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
| |
− | moon = {radius = 1736, defaultdisplay = 'dec', trackingcat = 'sur la Lune'},
| |
− | neptune = {radius = 24553, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
| |
− | oberon = {radius = 761, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
| |
− | phoebe = {radius = 110, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
| |
− | phobos = {radius = 11, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
| |
− | pluto = {radius = 1185, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
| |
− | rhea = {radius = 765, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
| |
− | saturn = {radius = 58232, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
| |
− | titan = {radius = 2575.5, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
| |
− | tethys = {radius = 530, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
| |
− | titania = {radius = 394, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
| |
− | triton = {radius = 1353, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
| |
− | umbriel = {radius = 584, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
| |
− | uranus = {radius = 25266, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
| |
− | venus = {radius = 6051.8, defaultdisplay = 'dec east', trackingcat = 'sur Vénus'},
| |
− | vesta = {radius = 260, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'}
| |
− | }
| |
− | globedata[''] = globedata.earth
| |
| | | |
− | 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
| + | if first then -- if NaN or nil, will skip down to final return |
− | local lang = mw.language.getContentLanguage()
| + | if first <= second then -- could match if both nil, but already checked that first is a number in last line |
− | local default_zoom = 13
| + | return math.random(first, second) |
− | | + | end |
− | local function makecat(cat, sortkey)
| + | return math.random(first) |
− | if type( sortkey ) == 'string' then
| + | end |
− | return '[[Category:' .. cat .. '|' .. sortkey .. ']]'
| + | return math.random() |
− | else
| |
− | return '[[Category:' .. cat .. ']]'
| |
− | end
| |
| end | | end |
| | | |
− | ----------------------------------------
| + | --[[ |
− | --Error handling
| + | order |
− | --[[ 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
| |
− | * D: more than one primary coord
| |
− | ]]--
| |
| | | |
− | local errorstring = ''
| + | Determine order of magnitude of a number |
| | | |
− | local function makeerror(args)
| + | Usage: |
− | local errormessage = ''
| + | {{#invoke: Math | order | value }} |
− | if args.message then
| + | ]] |
− | errormessage = '<strong class="error"> Coordonnées : ' .. args.message .. '</strong>'
| + | function z.order(frame) |
− | end
| + | local input_string = (frame.args[1] or frame.args.x or '0'); |
− | local errorcat = ''
| + | local input_number; |
− | if mw.title.getCurrentTitle().namespace == 0 then
| + | |
− | errorcat = makecat(i18n.errorcat, args.sortkey)
| + | input_number = z._cleanNumber( frame, input_string ); |
− | end
| + | if input_number == nil then |
− | errorstring = errormessage .. errorcat -- reinitializes the string to avoid absurdly long messages
| + | return '<strong class="error">Formatting error: Order of magnitude input appears non-numeric</strong>' |
− | return nil
| + | else |
| + | return z._order( input_number ) |
| + | end |
| end | | end |
− | | + | function z._order(x) |
− | local function showerrors()
| + | if x == 0 then return 0 end |
− | return errorstring
| + | return math.floor(math.log10(math.abs(x))) |
| end | | end |
| | | |
| + | --[[ |
| + | precision |
| | | |
| + | Detemines the precision of a number using the string representation |
| | | |
− | -- Distance computation
| + | Usage: |
− | function p._distance(a, b, globe) -- calcule la [[distance orthodromique]] en kilomètres entre deux points du globe | + | {{ #invoke: Math | precision | value }} |
− | | + | ]] |
− | globe = string.lower(globe or 'earth')
| + | function z.precision( frame ) |
− |
| + | local input_string = (frame.args[1] or frame.args.x or '0'); |
− | -- check arguments and converts degreees to radians
| + | local trap_fraction = frame.args.check_fraction or false; |
− | local latA, latB, longA, longB = a.latitude, b.latitude, a.longitude, b.longitude
| + | local input_number; |
− | if (not latA) or (not latB) or (not longA) or (not longB) then return
| + | |
− | error('coordinates missing, can\'t compute distance')
| + | if type( trap_fraction ) == 'string' then |
− | end
| + | trap_fraction = trap_fraction:lower(); |
− | if type(latA) ~= 'number' or type(latB) ~= 'number' or type(longA) ~= 'number' or type(longB) ~= 'number' then
| + | if trap_fraction == 'false' or trap_fraction == '0' or |
− | error('coordinates are not numeric, can\'t compute distance')
| + | trap_fraction == 'no' or trap_fraction == '' then |
− | end
| + | trap_fraction = false; |
− | if not globe or not globedata[globe] then
| + | else |
− | return error('globe: ' .. globe .. 'is not supported')
| + | trap_fraction = true; |
− | end
| + | end |
− |
| + | end |
− | -- calcul de la distance angulaire en radians
| + | |
− | local convratio = math.pi / 180 -- convertit en radians
| + | if trap_fraction then |
− | latA, latB, longA, longB = convratio * latA, convratio * latB, convratio * longA, convratio * longB
| + | local pos = string.find( input_string, '/', 1, true ); |
− | local cosangle = math.sin(latA) * math.sin(latB) + math.cos(latA) * math.cos(latB) * math.cos(longB - longA)
| + | if pos ~= nil then |
− | if cosangle >= 1 then -- may be above one because of rounding errors
| + | if string.find( input_string, '/', pos + 1, true ) == nil then |
− | return 0
| + | local denominator = string.sub( input_string, pos+1, -1 ); |
− | end
| + | local denom_value = tonumber( denominator ); |
− | local angle = math.acos(cosangle)
| + | if denom_value ~= nil then |
− | -- calcul de la distance en km
| + | return math.log10(denom_value); |
− | local radius = globedata[globe].radius
| + | end |
− | return radius * angle
| + | end |
− | end | + | end |
− | | + | end |
− | function p.distance(frame)
| + | |
− | local args = frame.args
| + | input_number, input_string = z._cleanNumber( frame, input_string ); |
− | return p._distance(
| + | if input_string == nil then |
− | {latitude = tonumber(args.latitude1), longitude = tonumber(args.longitude1)},
| + | return '<strong class="error">Formatting error: Precision input appears non-numeric</strong>' |
− | {latitude = tonumber(args.latitude2), longitude = tonumber(args.longitude2)},
| + | else |
− | args.globe)
| + | return z._precision( input_string ) |
| + | end |
| end | | end |
| + | function z._precision( x ) |
| + | x = string.upper( x ) |
| | | |
− | local function geoHackUrl(decLat, decLong, globe, displayformat, objectname, extraparams) | + | local decimal = string.find( x, '.', 1, true ) |
− | extraparams = extraparams or ''
| + | local exponent_pos = string.find( x, 'E', 1, true ) |
− | local geohacklatitude, geohacklongitude
| + | local result = 0; |
− | -- format latitude and longitude for the URL
| + | |
− | if tonumber(decLat) < 0 then
| + | if exponent_pos ~= nil then |
− | geohacklatitude = tostring(-tonumber(decLat)) .. '_S'
| + | local exponent = string.sub( x, exponent_pos + 1 ) |
− | else
| + | x = string.sub( x, 1, exponent_pos - 1 ) |
− | geohacklatitude = decLat .. '_N'
| + | result = result - tonumber( exponent ) |
− | end
| + | end |
− | if tonumber(decLong) < 0 then
| + | |
− | geohacklongitude = tostring(-tonumber(decLong)) .. '_W'
| + | if decimal ~= nil then |
− | elseif globedata[globe].defaultdisplay == 'dec west' then
| + | result = result + string.len( x ) - decimal |
− | geohacklongitude = decLong .. '_W'
| + | return result |
− | else
| + | end |
− | geohacklongitude = decLong .. '_E'
| + | |
− | end
| + | local pos = string.len( x ); |
− | -- prepares the 'paramss=' parameter
| + | while x:byte(pos) == string.byte('0') do |
− | local geohackparams = geohacklatitude .. '_' .. geohacklongitude .. '_' ..extraparams
| + | pos = pos - 1 |
− | -- concatenate parameteres for geohack
| + | result = result - 1 |
− | return i18n.geohackurl ..
| + | if pos <= 0 then |
− | "&pagename=" .. mw.uri.encode(mw.title.getCurrentTitle().prefixedText, "WIKI") ..
| + | return 0 |
− | "¶ms=" .. geohackparams ..
| + | end |
− | (objectname and ("&title=" .. mw.uri.encode(objectname)) or "")
| + | end |
| + | |
| + | return result |
| end | | end |
| | | |
− | --HTML builder for a geohack link | + | --[[ |
− | local function buildHTML(decLat, decLong, dmsLat, dmsLong, globe, displayformat, displayinline, displaytitle, objectname, extraparams)
| + | max |
− | -- geohack url
| |
− | local url = geoHackUrl(decLat, decLong, globe, displayformat, objectname, extraparams)
| |
− |
| |
− | -- displayed coordinates
| |
− | local displaycoords
| |
− | if string.sub(displayformat,1,3) == 'dec' then
| |
− | displaycoords = p.displaydec(decLat, decLong, displayformat)
| |
− | else
| |
− | displaycoords = {
| |
− | p.displaydmsdimension(dmsLat, displayformat),
| |
− | p.displaydmsdimension(dmsLong, displayformat),
| |
− | }
| |
− | end
| |
− |
| |
− | -- build coordinate in h-geo / h-card microformat
| |
− | local globeNode
| |
− | if globe and globe ~= 'earth' then
| |
− | globeNode = mw.html.create('data')
| |
− | :addClass('p-globe')
| |
− | :attr{ value = globe }
| |
− | :done()
| |
− | end
| |
− |
| |
− | local coordNode = mw.html.create('')
| |
− | if objectname then
| |
− | coordNode = mw.html.create('span')
| |
− | :addClass('h-card')
| |
− | :tag('data')
| |
− | :addClass('p-name')
| |
− | :attr{ value = objectname }
| |
− | :done()
| |
− | end
| |
− | coordNode
| |
− | :tag('span')
| |
− | :addClass('h-geo')
| |
− | :addClass('geo-' .. string.sub(displayformat,1,3))
| |
− | :tag('data')
| |
− | :addClass('p-latitude')
| |
− | :attr{ value = decLat }
| |
− | :wikitext( displaycoords[1] )
| |
− | :done()
| |
− | :wikitext(", ")
| |
− | :tag('data')
| |
− | :addClass('p-longitude')
| |
− | :attr{ value = decLong }
| |
− | :wikitext( displaycoords[2] )
| |
− | :done()
| |
− | :node( globeNode )
| |
− | :done()
| |
− |
| |
− | -- buid GeoHack link
| |
− | local root = mw.html.create('span')
| |
− | :addClass('plainlinks nourlexpansion')
| |
− | :attr('title', i18n.tooltip)
| |
− | :wikitext('[' .. url )
| |
− | :node(coordNode)
| |
− | :wikitext("]")
| |
− | :done()
| |
− |
| |
− | -- format result depending on args["display"] (nil, "inline", "title", "inline,title")
| |
− | local inlineText = displayinline and tostring(root) or ''
| |
− | local titleText = ''
| |
− | if displaytitle then
| |
− | local htmlTitle = mw.html.create('span')
| |
− | :attr{ id = 'coordinates' }
| |
− | :addClass( displayinline and 'noprint' or nil )
| |
− | :node( root )
| |
− | local frame = mw.getCurrentFrame()
| |
− | titleText = frame:extensionTag( 'indicator', tostring(htmlTitle), { name = 'coordinates' } )
| |
− | end
| |
− |
| |
− | return inlineText .. titleText
| |
− | end
| |
| | | |
− | local function zoom( extraparams )
| + | Finds the maximum argument |
− | local zoomParam = extraparams:match( '%f[%w]zoom: ?(%d+)' )
| |
− | if zoomParam then
| |
− | return zoomParam
| |
− | end
| |
− |
| |
− | local scale = extraparams:match( '%f[%w]scale: ?(%d+)' )
| |
− | if scale then
| |
− | return math.floor(math.log10( 1 / tonumber( scale ) ) * 3 + 25)
| |
− | end
| |
− |
| |
− | local extraType = extraparams:match( '%f[%w]type: ?(%w+)' )
| |
− | if extraType then
| |
− | local zoomType = {
| |
− | country = 5,
| |
− | state = 6,
| |
− | adm1st = 7,
| |
− | adm2nd = 8,
| |
− | city = 9,
| |
− | isle = 10,
| |
− | mountain = 10,
| |
− | waterbody = 10,
| |
− | airport = 12,
| |
− | landmark = 13,
| |
− | }
| |
− | return zoomType[ extraType ]
| |
− | end
| |
− | end
| |
| | | |
− | --HTML builder for a geohack link
| + | Usage: |
− | local function buildMaplinkHTML( decLat, decLong, dmsLat, dmsLong, globe, displayformat, displayinline, displaytitle, objectname, extraparams )
| + | {{#invoke:Math| max | value1 | value2 | ... }} |
− | -- displayed coordinates
| + | OR |
− | local displaycoords
| + | {{#invoke:Math| max }} |
− | if string.sub(displayformat,1,3) == 'dec' then
| |
− | displaycoords = p.displaydec(decLat, decLong, displayformat)
| |
− | else
| |
− | displaycoords = {
| |
− | p.displaydmsdimension(dmsLat, displayformat),
| |
− | p.displaydmsdimension(dmsLong, displayformat),
| |
− | }
| |
− | end
| |
− |
| |
− | -- JSON for maplink
| |
− | local jsonParams = {
| |
− | type = 'Feature',
| |
− | geometry = {
| |
− | type ='Point',
| |
− | coordinates = {
| |
− | math_mod._round( decLong, 6 ), -- max precision in GeoJSON format
| |
− | math_mod._round( decLat, 6 )
| |
− | }
| |
− | },
| |
− | properties = {
| |
− | ['marker-color'] = "228b22",
| |
− | }
| |
− | }
| |
− | if objectname then
| |
− | jsonParams.properties.title = objectname
| |
− | end
| |
− | -- ajout de geoshape via externaldata
| |
− | local geoshape = extraparams:match( '%f[%w]geoshape: ?(Q%d+)' )
| |
− | if not geoshape and displaytitle and mw.wikibase.getEntity() then
| |
− | geoshape = mw.wikibase.getEntity().id
| |
− | end
| |
− | if geoshape then
| |
− | jsonParams = {
| |
− | jsonParams,
| |
− | {
| |
− | type = 'ExternalData',
| |
− | service = 'geoshape',
| |
− | ids = geoshape,
| |
− | properties = {
| |
− | ['fill-opacity'] = 0.2
| |
− | }
| |
− | }
| |
− | }
| |
− | end
| |
| | | |
− | local maplink = mw.getCurrentFrame():extensionTag{
| + | When used with no arguments, it takes its input from the parent |
− | name = 'maplink',
| + | frame. Note, any values that do not evaluate to numbers are ignored. |
− | content = mw.text.jsonEncode( jsonParams ),
| + | ]] |
− | args = {
| + | function z.max( frame ) |
− | text = displaycoords[1] .. ", " .. displaycoords[2],
| + | local args = frame.args; |
− | zoom = zoom( extraparams ) or default_zoom,
| + | |
− | latitude = decLat,
| + | if args[1] == nil then |
− | longitude = decLong,
| + | local parent = frame:getParent(); |
− | }
| + | args = parent.args; |
− | }
| + | end |
− |
| + | local max_value = nil; |
− | -- format result depending on args["display"] (nil, "inline", "title", "inline,title")
| + | |
− | local inlineText = displayinline and maplink or ''
| + | local i = 1; |
− | local titleText = ''
| + | while args[i] ~= nil do |
− | if displaytitle then
| + | local val = z._cleanNumber( frame, args[i] ); |
− | local htmlTitle = mw.html.create('span')
| + | if val ~= nil then |
− | :attr{ id = 'coordinates' }
| + | if max_value == nil or val > max_value then |
− | :addClass( displayinline and 'noprint' or nil )
| + | max_value = val; |
− | :wikitext( maplink )
| + | end |
− | local frame = mw.getCurrentFrame()
| + | end |
− | titleText = frame:extensionTag( 'indicator', tostring(htmlTitle), { name = 'coordinates' } )
| + | i = i + 1; |
− | end
| + | end |
− |
| + | |
− | return inlineText .. titleText
| + | return max_value |
| end | | end |
| | | |
− | -- dms specific funcions | + | --[[ |
| + | min |
| | | |
− | local function twoDigit( value )
| + | Finds the minimum argument |
− | if ( value < 10 ) then
| |
− | value = '0' .. lang:formatNum( value )
| |
− | else
| |
− | value = lang:formatNum( value )
| |
− | end
| |
− | return value
| |
− | end
| |
| | | |
− | function p.displaydmsdimension(valuetable, format) -- formate en latitude ou une longitude dms
| + | Usage: |
− | local str = ''
| + | {{#invoke:Math| min | value1 | value2 | ... }} |
− | local direction = valuetable.direction
| + | OR |
− | local degrees, minutes, seconds = '', '', ''
| + | {{#invoke:Math| min }} |
− | local dimension
| |
| | | |
− | if format == 'dms long' then
| + | When used with no arguments, it takes its input from the parent |
− | direction = i18n[direction .. 'long']
| + | frame. Note, any values that do not evaluate to numbers are ignored. |
− | else
| + | ]] |
− | direction = i18n[direction]
| + | function z.min( frame ) |
− | end
| + | local args = frame.args; |
− | degrees = lang:formatNum( valuetable.degrees ) .. i18n.degrees
| + | |
− |
| + | if args[1] == nil then |
− | if valuetable.minutes then
| + | local parent = frame:getParent(); |
− | minutes = twoDigit( valuetable.minutes ) .. i18n.minutes
| + | args = parent.args; |
− | end
| + | end |
− | if valuetable.seconds then
| + | local min_value = nil; |
− | seconds = twoDigit( valuetable.seconds ) .. i18n.seconds
| + | |
− | end
| + | local i = 1; |
− | return degrees .. minutes .. seconds .. direction
| + | while args[i] ~= nil do |
| + | local val = z._cleanNumber( frame, args[i] ); |
| + | if val ~= nil then |
| + | if min_value == nil or val < min_value then |
| + | min_value = val; |
| + | end |
| + | end |
| + | i = i + 1; |
| + | end |
| + | |
| + | return min_value |
| end | | end |
| | | |
− | local function validdms(coordtable)
| + | --[[ |
− | local direction = coordtable.direction
| + | round |
− | local degrees = coordtable.degrees or 0
| |
− | local minutes = coordtable.minutes or 0
| |
− | local seconds = coordtable.seconds or 0
| |
− | local dimension = coordtable.dimension
| |
− | if not dimension then
| |
− | if direction == 'N' or direction == 'S' then
| |
− | dimension = 'latitude'
| |
− | elseif direction == 'E' or direction == 'W' then
| |
− | dimension = 'longitude'
| |
− | else
| |
− | makeerror({message = i18n.invalidNSEW, sortkey = 'A'})
| |
− | return false
| |
− | end
| |
− | end
| |
| | | |
− | if type(degrees) ~= 'number' or type(minutes) ~= 'number' or type(seconds) ~= 'number' then
| + | Rounds a number to specified precision |
− | makeerror({message = i18n.invalidFormat, sortkey = 'A'})
| |
− | return false
| |
− | end
| |
− |
| |
− | if dimension == 'latitude' and direction ~= 'N' and direction ~= 'S' then
| |
− | makeerror({message = i18n.invalidNS, sortkey = 'A'})
| |
− | return false
| |
− | end
| |
− | if dimension == 'longitude' and direction ~= 'W' and direction ~= 'E' then
| |
− | makeerror({message = i18n.invalidEW, sortkey = 'A'})
| |
− | return false
| |
− | end
| |
− |
| |
− | if dimension == 'latitude' and degrees > 90 then
| |
− | makeerror({message = i18n.latitude90, sortkey = 'A'})
| |
− | return false
| |
− | end
| |
− |
| |
− | if dimension == 'longitude' and degrees > 360 then
| |
− | makeerror({message = i18n.longitude360, sortkey = 'A'})
| |
− | return false
| |
− | end
| |
− |
| |
− | if degrees < 0 or minutes < 0 or seconds < 0 then
| |
− | makeerror({message = i18n.negativeCoode, sortkey = 'A'})
| |
− | return false
| |
− | end
| |
− |
| |
− | if minutes > 60 or seconds > 60 then
| |
− | makeerror({message = i18n.minSec60, sortkey = 'A'})
| |
− | return false
| |
− | end
| |
− | if (math.floor(degrees) ~= degrees and minutes ~= 0) or (math.floor(minutes) ~= minutes and seconds ~= 0) then
| |
− | makeerror({message = i18n.dmIntergers, sortkey = 'A'})
| |
− | return false
| |
− | end
| |
− | return true
| |
− | end
| |
| | | |
− | local function builddmsdimension(degrees, minutes, seconds, direction, dimension)
| + | Usage: |
− | -- no error checking, done in function validdms
| + | {{#invoke:Math | round | value | precision }} |
− | local dimensionobject = {}
| + | |
− |
| + | --]] |
− | -- direction and dimension (= latitude or longitude)
| + | function z.round(frame) |
− | dimensionobject.direction = direction
| + | local value, precision; |
− | if dimension then
| + | |
− | dimensionobject.dimension = dimension
| + | value = z._cleanNumber( frame, frame.args[1] or frame.args.value or 0 ); |
− | elseif direction == 'N' or direction == 'S' then
| + | precision = z._cleanNumber( frame, frame.args[2] or frame.args.precision or 0 ); |
− | dimensionobject.dimension = 'latitude'
| + | |
− | elseif direction == 'E' or direction == 'W' then
| + | if value == nil or precision == nil then |
− | dimensionobject.dimension = 'longitude'
| + | return '<strong class="error">Formatting error: Round input appears non-numeric</strong>' |
− | end
| + | else |
− |
| + | return z._round( value, precision ); |
− | -- degrees, minutes, seconds
| + | end |
− | 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 z._round( value, precision ) |
− | function p._parsedmsstring(str, dimension) -- prend une séquence et donne des noms aux paramètres | + | local rescale = math.pow( 10, precision ); |
− | -- output table: {latitude=, longitude = , direction = }
| + | return math.floor( value * rescale + 0.5 ) / rescale; |
− | if type( str ) ~= 'string' then
| |
− | return nil
| |
− | end
| |
− | str = mw.ustring.gsub( mw.ustring.upper( str ), '%a+', coordParse )
| |
− | if not tonumber( str ) and not str:find( '/' ) and str:find( '°' ) then
| |
− | local str2 = mw.ustring.gsub( str, '[°″′\"\'\194\160 ]+', '/' )
| |
− | -- avoid cases were there is degree ans seconds but no minutes
| |
− | if not mw.ustring.find( str, '[″"]' ) or mw.ustring.find( str, '%d[′\'][ \194\160%d]' ) then
| |
− | str = str2
| |
− | end
| |
− | end
| |
− | if not tonumber(str) and not string.find(str, '/') then
| |
− | makeerror({message = i18n.invalidFormat, sortkey= 'A'})
| |
− | return nil
| |
− | end
| |
− | args = mw.text.split(str, '/', true)
| |
− | if #args > 4 then
| |
− | makeerror({message = i18n.tooManyParam, sortkey= 'A' })
| |
− | end
| |
− | local direction = mw.text.trim(args[#args])
| |
− | table.remove(args)
| |
− | local degrees, minutes, seconds = args[1], args[2], args[3]
| |
− | local dimensionobject = builddmsdimension(degrees, minutes, seconds, direction, dimension)
| |
− | if validdms(dimensionobject) then
| |
− | return dimensionobject
| |
− | else
| |
− | return nil
| |
− | end
| |
| end | | end |
| | | |
− | --- decimal specific functions | + | --[[ |
− | function p.displaydec(latitude, longitude, format)
| + | precision_format |
− | lat = lang:formatNum( latitude )
| |
− | long = lang:formatNum( longitude )
| |
− |
| |
− | if format == 'dec west' or format == 'dec east' then
| |
− | local symbolNS, symbolEW = i18n.N, i18n.E
| |
− | if latitude < 0 then
| |
− | symbolNS = i18n.S
| |
− | lat = lat:sub( 2 )
| |
− | end
| |
− | if format == 'dec west' then
| |
− | symbolEW = i18n.W
| |
− | end
| |
− | if longitude < 0 then
| |
− | long = lang:formatNum( 360 + longitude )
| |
− | end
| |
− |
| |
− | return { lat .. i18n.degrees .. symbolNS, long .. i18n.degrees .. symbolEW }
| |
− |
| |
− | else
| |
− | return { lat, long }
| |
− | end
| |
− | end
| |
| | | |
| + | Rounds a number to the specified precision and formats according to rules |
| + | originally used for {{template:Rnd}}. Output is a string. |
| | | |
− | local function parsedec(dec, coordtype, globe) -- coordtype = latitude or longitude
| + | Usage: |
− | dec = mw.text.trim(dec)
| + | {{#invoke: Math | precision_format | number | precision }} |
− | if not dec then
| + | ]] |
− | return nil
| + | function z.precision_format( frame ) |
− | end
| + | -- For access to Mediawiki built-in formatter. |
− | if coordtype ~= 'latitude' and coordtype ~= 'longitude' then
| + | local lang = mw.getContentLanguage(); |
− | makeerror({'invalid coord type', sortkey = "A"})
| + | |
− | return nil
| + | local value_string, value, precision; |
− | end
| + | value, value_string = z._cleanNumber( frame, frame.args[1] or 0 ); |
− | local numdec = tonumber(dec) -- numeric value, kept separated as it looses significant zeros
| + | precision = z._cleanNumber( frame, frame.args[2] or 0 ); |
− | if not numdec then -- tries the decimal + direction format
| + | |
− | dec = mw.ustring.gsub( mw.ustring.upper( dec ), '%a+', coordParse )
| + | -- Check for non-numeric input |
− | local direction = mw.ustring.sub(dec, mw.ustring.len(dec), mw.ustring.len(dec))
| + | if value == nil or precision == nil then |
− | dec = mw.ustring.sub(dec, 1, mw.ustring.len(dec)-2) -- removes the /N at the end
| + | return '<strong class="error">Formatting error: invalid input when rounding</strong>' |
− | if not dec or not tonumber(dec) then
| + | end |
− | return nil
| + | |
− | end
| + | local current_precision = z._precision( value ); |
− | if direction == 'N' or direction == 'E' or direction == 'W' and globedata[globe].defaultdisplay == 'dec west' then
| |
− | return dec
| |
− | elseif direction == 'W' or direction == 'S' then
| |
− | return '-' .. dec
| |
− | else
| |
− | if coordtype == 'latitude' then
| |
− | makeerror({message = i18n.invalidNS, sortkey = 'A'})
| |
− | else
| |
− | makeerror({message = i18n.invalidEW, sortkey = 'A'})
| |
− | end
| |
− | return nil
| |
− | end
| |
− | end
| |
| | | |
− | if coordtype == 'latitude' and math.abs(numdec) > 90 then
| + | local order = z._order( value ); |
− | makeerror({message = i18n.latitude90 , sortkey = 'A'})
| + | |
− | return nil
| + | -- Due to round-off effects it is neccesary to limit the returned precision under |
− | end
| + | -- some circumstances because the terminal digits will be inaccurately reported. |
− | if coordtype == 'longitude' and math.abs(numdec) > 360 then
| + | if order + precision >= 14 then |
− | makeerror({message = i18n.longitude360 , sortkey = 'A'})
| + | local orig_precision = z._precision( value_string ); |
− | return nil
| + | if order + orig_precision >= 14 then |
− | end
| + | precision = 13 - order; |
− | return dec
| + | end |
− | end | + | end |
| | | |
− | -- dms/dec conversion functions | + | -- If rounding off, truncate extra digits |
− | local function convertprecision(precision) -- converts a decimal precision like "2" into "dm" | + | if precision < current_precision then |
− | if precision >= 3 then
| + | value = z._round( value, precision ); |
− | return 'dms'
| + | current_precision = z._precision( value ); |
− | elseif precision >=1 then
| + | end |
− | return 'dm'
| + | |
− | else
| + | local formatted_num = lang:formatNum( math.abs(value) ); |
− | return 'd'
| + | local sign; |
− | end
| + | |
− | end
| + | -- Use proper unary minus sign rather than ASCII default |
| + | if value < 0 then |
| + | sign = '−'; |
| + | else |
| + | sign = ''; |
| + | end |
| + | |
| + | -- Handle cases requiring scientific notation |
| + | if string.find( formatted_num, 'E', 1, true ) ~= nil or math.abs(order) >= 9 then |
| + | value = value * math.pow( 10, -order ); |
| + | current_precision = current_precision + order; |
| + | precision = precision + order; |
| + | formatted_num = lang:formatNum( math.abs(value) ); |
| + | else |
| + | order = 0; |
| + | end |
| + | formatted_num = sign .. formatted_num; |
| + | |
| + | -- Pad with zeros, if needed |
| + | if current_precision < precision then |
| + | local padding; |
| + | if current_precision <= 0 then |
| + | if precision > 0 then |
| + | local zero_sep = lang:formatNum( 1.1 ); |
| + | formatted_num = formatted_num .. zero_sep:sub(2,2); |
| | | |
− | local function determinedmsprec(decs) -- returns the most precision for a dec2dms conversion, depending on the most precise value in the decs table
| + | padding = precision; |
− | local precision = 0
| + | if padding > 20 then |
− | for d, val in ipairs(decs) do
| + | padding = 20; |
− | precision = math.max(precision, math_mod._precision(val))
| + | end |
− | end
| + | |
− | return convertprecision(precision)
| + | formatted_num = formatted_num .. string.rep( '0', padding ); |
− | end | + | end |
| + | else |
| + | padding = precision - current_precision |
| + | if padding > 20 then |
| + | padding = 20; |
| + | end |
| + | formatted_num = formatted_num .. string.rep( '0', padding ); |
| + | end |
| + | end |
| | | |
− | local function dec2dms_d(dec)
| + | -- Add exponential notation, if necessary. |
− | local degrees = math_mod._round( dec, 0 )
| + | if order ~= 0 then |
− | return degrees
| + | -- Use proper unary minus sign rather than ASCII default |
| + | if order < 0 then |
| + | order = '−' .. lang:formatNum( math.abs(order) ); |
| + | else |
| + | order = lang:formatNum( order ); |
| + | end |
| + | |
| + | formatted_num = formatted_num .. '<span style="margin:0 .15em 0 .25em">×</span>10<sup>' .. order .. '</sup>' |
| + | end |
| + | |
| + | return formatted_num; |
| end | | end |
| | | |
− | local function dec2dms_dm(dec)
| + | --[[ |
− | dec = math_mod._round( dec * 60, 0 )
| + | Helper function that interprets the input numerically. If the |
− | local minutes = dec % 60
| + | input does not appear to be a number, attempts evaluating it as |
− | dec = math.floor( (dec - minutes) / 60 )
| + | a parser functions expression. |
− | local degrees = dec % 360
| + | ]] |
− | return degrees, minutes
| |
− | end
| |
| | | |
− | local function dec2dms_dms(dec)
| + | function z._cleanNumber( frame, number_string ) |
− | dec = math_mod._round( dec * 60 * 60, 0 )
| + | if number_string == nil or number_string:len() == 0 then |
− | local seconds = dec % 60
| + | return nil, nil; |
− | dec = math.floor( (dec - seconds) / 60 )
| + | end |
− | local minutes = dec % 60
| + | |
− | dec = math.floor( (dec - minutes) / 60 )
| + | -- Attempt basic conversion |
− | local degrees = dec % 360
| + | local number = tonumber( number_string ) |
− | return degrees, minutes, seconds
| + | |
| + | -- If failed, attempt to evaluate input as an expression |
| + | if number == nil then |
| + | local attempt = frame:preprocess( '{{#expr: ' .. number_string .. '}}' ); |
| + | attempt = tonumber( attempt ); |
| + | if attempt ~= nil then |
| + | number = attempt; |
| + | number_string = tostring( number ); |
| + | else |
| + | number = nil; |
| + | number_string = nil; |
| + | end |
| + | else |
| + | -- String is valid but may contain padding, clean it. |
| + | number_string = number_string:match( "^%s*(.-)%s*$" ); |
| + | end |
| + | |
| + | return number, number_string; |
| end | | end |
| | | |
− | function p._dec2dms(dec, coordtype, precision, globe) -- coordtype: latitude or longitude
| + | return z |
− | local degrees, minutes, seconds
| |
− |
| |
− | -- vérification du globe
| |
− | if not ( globe and globedata[ globe ] ) then
| |
− | globe = 'earth'
| |
− | end
| |
− |
| |
− | -- precision
| |
− | if not precision or precision == '' then
| |
− | precision = determinedmsprec({dec})
| |
− | end
| |
− | if precision ~= 'd' and precision ~= 'dm' and precision ~= 'dms' then
| |
− | return makeerror({sortkey = 'C'})
| |
− | end
| |
− | local dec = tonumber(dec)
| |
− |
| |
− | -- direction
| |
− | local direction
| |
− | if coordtype == 'latitude' then
| |
− | if dec < 0 then
| |
− | direction = 'S'
| |
− | else
| |
− | direction = 'N'
| |
− | end
| |
− | elseif coordtype == 'longitude' then
| |
− | if dec < 0 or globedata[globe].defaultdisplay == 'dec west' 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
| |
− | degrees, minutes, seconds = dec2dms_dms(dec)
| |
− | elseif precision == 'dm' then
| |
− | degrees, minutes = dec2dms_dm(dec)
| |
− | else
| |
− | degrees = dec2dms_d(dec)
| |
− | end
| |
− | return builddmsdimension(degrees, minutes, seconds, direction)
| |
− | end
| |
− | | |
− | function p.dec2dms(frame) -- legacy function somewhat cumbersome syntax
| |
− | args = frame.args
| |
− | local dec = args[1]
| |
− | if not tonumber(dec) then
| |
− | makeerror({message = i18n.invalidFormat, sortkey = 'A'})
| |
− | return showerrors()
| |
− | end
| |
− | local dirpositive = string.lower(args[2] or '')
| |
− | local dirnegative = string.lower(args[3] or '')
| |
− | local precision = string.lower(args[4] or '')
| |
− | local displayformat, coordtype
| |
− |
| |
− | if dirpositive == 'n' or dirpositive == 'nord' then
| |
− | coordtype = 'latitude'
| |
− | else
| |
− | coordtype = 'longitude'
| |
− | end
| |
− | if dirpositive == 'nord' or dirpositive == 'est' or dirnegative == 'ouest' or dirnegative == 'sud' then
| |
− | displayformat = 'dms long'
| |
− | end
| |
− | local coordobject = p._dec2dms(dec, coordtype, precision)
| |
− | if coordobject then
| |
− | return p.displaydmsdimension(coordobject, displayformat) .. showerrors()
| |
− | else
| |
− | return showerrors()
| |
− | end
| |
− | 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 = i18n.noCardinalDirection, sortkey = 'A'})
| |
− | return nil
| |
− | else
| |
− | makeerror({message = i18n.invalidDirection, 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
| |
− | local dmsobject = p._parsedmsstring(args[1])
| |
− | if dmsobject then
| |
− | return p._dms2dec(dmsobject) -- coordonnées sous la fore 23/22/N
| |
− | else
| |
− | return showerrors()
| |
− | end
| |
− | else
| |
− | return p._dms2dec({direction = args[1], degrees = tonumber(args[2]), minutes = tonumber(args[3]), seconds = tonumber(args[4])})
| |
− | end
| |
− | end
| |
− | | |
− | -- Wikidata
| |
− | local function convertwikidataprecision(precision) -- converts a decima like "0.1" into "dm"
| |
− | if precision < 0.016 then
| |
− | return 'dms'
| |
− | elseif precision < 1 then
| |
− | return 'dm'
| |
− | else
| |
− | return 'd'
| |
− | end
| |
− | end
| |
− | | |
− | local function wikidatacoords(query)
| |
− | query = query or {property = 'p625'}
| |
− | query.formatting = 'raw'
| |
− | 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
| |
− | -- Wikidata does not handle correctly +West longitudes
| |
− | if globedata[ coords.globe ] and globedata[ coords.globe ].defaultdisplay == 'dec west' then
| |
− | coords.longitude = math.abs( coords.longitude )
| |
− | end
| |
− | return coords.latitude, coords.longitude, coords.globe or 'earth', convertwikidataprecision(coords.precision or .001)
| |
− | end
| |
− | return nil
| |
− | end
| |
− | | |
− | | |
− | local function wikidatacat(globe)
| |
− | --catbase= Article géolocalisé sur Terre
| |
− | local entitycat = mw.wikibase.getEntity()
| |
− |
| |
− | local basecat = 'Article géolocalisé'
| |
− | local finalcat = {}
| |
− | --BADGES
| |
− | if entitycat then
| |
− | --BADGES
| |
− | for i, badgeId in ipairs( entitycat.sitelinks['frwiki'].badges ) do
| |
− | if badgeId == 'Q17437796' then
| |
− | basecat=string.gsub(basecat, "Article géolocalisé", "Article de qualité géolocalisé")
| |
− | end
| |
− | if badgeId == 'Q17437798' then
| |
− | basecat=string.gsub(basecat, "Article géolocalisé", "Bon article géolocalisé")
| |
− | end
| |
− | end
| |
− | end
| |
− | | |
− | if globe == 'earth' then
| |
− | if entitycat and entitycat.claims then
| |
− | local country=entitycat.claims['P17']
| |
− | if not country then
| |
− | --pas pays à récupérer
| |
− | basecat=basecat .. ' sur Terre'
| |
− | table.insert(finalcat,basecat)
| |
− | else
| |
− | --parfois plusieurs pays
| |
− | for i, paysId in ipairs( country ) do
| |
− | --on fait confiance au label wikidata
| |
− | local gdataone,qid
| |
− |
| |
− | if paysId.mainsnak.snaktype == 'value' then
| |
− | qid=paysId.mainsnak.datavalue.value['numeric-id']
| |
− | gdataone=gdata.data[qid]
| |
− | else
| |
− | --Bir Tawil n'a pas de pays connu
| |
− | qid='?'
| |
− | end
| |
− | if gdataone ~= nil then
| |
− | local prep=genre[gdataone['genre']]['en'] or 'en '
| |
− | local thecat=basecat .. ' '..prep ..mw.wikibase.label( 'Q'.. qid)
| |
− | if mw.title.new('category:'..thecat).exists then
| |
− | table.insert(finalcat,thecat)
| |
− | else
| |
− | --Dommage!
| |
− | mw.log(thecat .. ' à créer')
| |
− | end
| |
− | else
| |
− | --pas d'id?
| |
− | mw.log(qid .. ' à paramétrer')
| |
− | end
| |
− | end
| |
− | if #finalcat == 0 then
| |
− | --pas pays à récupérer
| |
− | basecat=basecat .. ' sur Terre'
| |
− | table.insert(finalcat,basecat)
| |
− | end
| |
− | end
| |
− | else
| |
− | --pas wikidata
| |
− | basecat=basecat .. ' sur Terre'
| |
− | table.insert(finalcat,basecat)
| |
− | end
| |
− | elseif globedata[globe] then
| |
− | basecat=basecat .. ' ' .. globedata[globe].trackingcat
| |
− | table.insert(finalcat,basecat)
| |
− | else
| |
− | basecat=basecat .. ' extraterrestre'
| |
− | table.insert(finalcat,basecat)
| |
− | end
| |
− | return finalcat
| |
− | end
| |
− | | |
− | -- main function for displaying coordinates
| |
− | function p._coord(args)
| |
− | | |
− | -- I declare variable
| |
− | local displayformat = args.format -- string: one of: 'dms', 'dms long', 'dec', 'dec east' and 'dec west'
| |
− | local displayplace = string.lower(args.display or 'inline') --string: one of 'inline', 'title' or 'inline,title'
| |
− | local objectname = (args.name ~= '') and args.name -- string: name of the title displayed in geohack
| |
− | local notes = (' ' and args.notes) or '' -- string: notes to de displayed after coordinates
| |
− | local wikidata = args.wikidata -- string: set to "true" if needed
| |
− | local wikidataquery = args.wikidataquery -- table: see [[Module:Wikidata]] see function wikidatacoords
| |
− | local dmslatitude, dmslongitude -- table (when created)
| |
− | local extraparams = args.extraparams or '' -- string (legacy, corresponds to geohackparams)
| |
− | local trackingstring = '' -- tracking cats except error cats (already in errorstring)
| |
− | local rawlat, rawlong = args.latitude, args.longitude
| |
− | if rawlat == '' then rawlat = nil end
| |
− | if rawlong == '' then rawlong = nil end
| |
− | local globe = string.lower( args.globe or extraparams:match('globe:(%a+)') or '' ) -- string: see the globedata table for accepted values
| |
− | local latitude, longitude, precision, dmslatitude, dmslongitude -- latitude and longitude in decimal / dmslatitude and dmslongitude: tables withdms coords
| |
− | local maplink = true -- use maplink whenever it is possible
| |
− |
| |
− | -- II extract coordinates from Wikitext
| |
− | if (rawlat or rawlong) then
| |
− | if (not rawlat) or (not rawlong) then -- if latitude is provided so should be longitude
| |
− | makeerror({message = i18n.coordMissing, sortkey = 'A'})
| |
− | return showerrors()
| |
− | end
| |
− | latitude = parsedec(rawlat, 'latitude', globe)
| |
− | | |
− | if latitude then -- if latitude is decimal
| |
− | longitude = parsedec(rawlong, 'longitude', globe) -- so should be longitude
| |
− | precision = determinedmsprec({latitude, longitude}) -- before conversion from string to number for trailing zeros
| |
− | if not latitude or not longitude then
| |
− | if errorstring == '' then
| |
− | makeerror({message = i18n.invalidFormat, sortkey = 'A'})
| |
− | end
| |
− | return showerrors()
| |
− | end
| |
− | dmslatitude, dmslongitude = p._dec2dms(latitude, 'latitude', precision), p._dec2dms(longitude, 'longitude', precision, globe)
| |
− | latitude, longitude = tonumber(latitude), tonumber(longitude)
| |
− | else -- if latitude is not decimal try to parse it as a dms string
| |
− | dmslatitude, dmslongitude = p._parsedmsstring(args.latitude, 'latitude'), p._parsedmsstring(args.longitude, 'longitude')
| |
− | if not dmslatitude or not dmslongitude then
| |
− | return showerrors()
| |
− | end
| |
− | latitude, longitude = p._dms2dec(dmslatitude), p._dms2dec(dmslongitude)
| |
− | end
| |
− | end
| |
− | | |
− | -- III extract coordinate data from Wikidata and compare them to local data
| |
− | local wikidatalatitude, wikidatalongitude, wikidataglobe, wikidataprecision
| |
− | if wikidata == 'true' then
| |
− | wikidatalatitude, wikidatalongitude, wikidataglobe, wikidataprecision = wikidatacoords(wikidataquery)
| |
− |
| |
− | if wikidatalatitude and latitude and longitude 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, precision = wikidatalatitude, wikidatalongitude, wikidataglobe, wikidataprecision
| |
− | dmslatitude, dmslongitude = p._dec2dms(latitude, 'latitude', precision), p._dec2dms(longitude, 'longitude', precision, globe)
| |
− | trackingstring = trackingstring .. makecat(i18n.throughwikidata)
| |
− | end
| |
− |
| |
− | if latitude and not wikidatalatitude then
| |
− | if mw.title.getCurrentTitle().namespace == 0 then
| |
− | trackingstring = trackingstring .. makecat(i18n.nowikidata)
| |
− | end
| |
− | end
| |
− | end
| |
− | | |
− | | |
− | -- exit if stil no latitude or no 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
| |
− | | |
− | -- IV best guesses for missing parameters
| |
− |
| |
− | --- globe
| |
− | if globe == '' then
| |
− | globe = 'earth'
| |
− | end
| |
− | if not globedata[globe] then
| |
− | makeerror({message = i18n.invalidGlobe .. globe})
| |
− | globe = 'earth'
| |
− | end
| |
− | if globe ~= 'earth' then
| |
− | extraparams = extraparams .. '_globe:' .. globe -- pas de problème si le globe est en double
| |
− | maplink = false
| |
− | end
| |
− |
| |
− | --- diplayformat
| |
− | if not displayformat or displayformat == '' then
| |
− | displayformat = globedata[globe].defaultdisplay
| |
− | 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
| |
− | --local cattoappend=globedata[globe].trackingcat
| |
− | --Récupération des badges
| |
− | local cats=wikidatacat(globe)
| |
− | for i, cat in ipairs( cats ) do
| |
− | trackingstring = trackingstring .. makecat(cat)
| |
− | end
| |
− |
| |
− | end
| |
− |
| |
− | -- V geodata
| |
− | local geodata = ''
| |
− | if latitude and longitude then
| |
− | local latstring, longstring = tostring(latitude), tostring(longitude)
| |
− | local primary = ''
| |
− | | |
− | local frame = mw.getCurrentFrame()
| |
− | local geodataparams = {[1] = latstring, [2] = longstring, [3] = extraparams }
| |
− | if displaytitle then
| |
− | geodataparams[4] = 'primary'
| |
− | end
| |
− | if objectname then
| |
− | geodataparams.name = objectname
| |
− | end
| |
− | geodata = frame:callParserFunction('#coordinates', geodataparams )
| |
− | if string.find(geodata, 'error') then -- the only error that has not been caught yet is primary key
| |
− | geodata = ''
| |
− | makeerror({sortkey='D'})
| |
− | end
| |
− | end
| |
− | -- VI final output
| |
− | local mainstring = ''
| |
− | if maplink then
| |
− | mainstring = buildMaplinkHTML(latitude, longitude, dmslatitude, dmslongitude, globe, displayformat, displayinline, displaytitle, objectname,extraparams )
| |
− | else
| |
− | mainstring = buildHTML(latitude, longitude, dmslatitude, dmslongitude, globe, displayformat, displayinline, displaytitle, objectname,extraparams )
| |
− | end
| |
− |
| |
− | return mainstring .. notes .. trackingstring .. geodata .. 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 %2 == 1 then -- if the number of args is odd, the last one provides formatting parameters
| |
− | args.extraparams = numericargs[#numericargs]
| |
− | if #numericargs == 1 and tonumber(numericargs[1]) then
| |
− | makeerror({message = i18n.coordMissing, sortkey = 'A'})
| |
− | return showerrors()
| |
− | end
| |
− | 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
| |
− | return p._coord(args)
| |
− | end
| |
− | | |
− | function p.Coord(frame)
| |
− | return p.coord(frame)
| |
− | end
| |
− | | |
− | function p.latitude(frame) -- helper function pour infobox, à déprécier
| |
− | local args = frame.args
| |
− | local latitude = frame.args[1]
| |
− | if latitude and mw.text.trim(latitude) ~= '' then
| |
− | return latitude
| |
− | elseif frame.args['wikidata'] == 'true' then
| |
− | local lat, long = wikidatacoords()
| |
− | return lat
| |
− | end
| |
− | end
| |
− | function p.longitude(frame) -- helper function pour infobox, à déprécier
| |
− | local args = frame.args
| |
− | local longitude = frame.args[1]
| |
− | if longitude and mw.text.trim(longitude) ~= '' then
| |
− | return longitude
| |
− | elseif frame.args['wikidata'] == 'true' then
| |
− | local lat, long = wikidatacoords()
| |
− | return long
| |
− | end
| |
− | end
| |
− | | |
− | | |
− | return p
| |