Módulo:Coordenadas
This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
Descrição
Este módulo implementa a predefinição {{Coor dms}}
. Por favor consulte a predefinição para mais instruções.
Uso
Outra documentação:
local math_mod = require( "Módulo:Math" )
local p = {}
local current_page = mw.title.getCurrentTitle()local page_name = mw.uri.encode( current_page.prefixedText, 'WIKI' );
local coord_link = '//tools.wmflabs.org/geohack/geohack.php?pagename=' .. page_name .. '¶ms='
--Carregando a lista em /Au/Aux/A
local gdata
local success, resultado = pcall (mw.loadData, "Módulo:Bandeira/Dados" )
if success then
gdata = resultado
else
-- Banco de dados minimo em caso de bug em Módulo:Língua/Dados
gdata={}
gdata.data={};
gdata.data[142]={qid="Q45", label="Portugal", genre="ms"}
end
local i18n = {
N = 'N',
Nlong = 'norte',
W = 'O',
Wlong = 'oeste',
E = 'L',
Elong = 'leste',
S = 'S',
Slong = 'sul',
degrees = '° ',
minutes = '′ ',
seconds = '″ ',
geohackurl = 'http://tools.wmflabs.org/geohack/geohack.php?language=pt',
tooltip = 'Mapas, vistas aéreas, etc.',
errorcat = '!Páginas com as etiquetas de coordenadas malformadas',
sameaswikidata = '!Páginas com coordenadas similares na Wikidata',
notaswikidata = '!Páginas com coordenadas diferente na Wikidata',
nowikidata = '!Páginas sem coordenadas Wikidata',
throughwikidata = '!Artigos com coordenadas no Wikidata',
invalidFormat = 'formato inválido', -- 'invalid coordinate format',
invalidNSEW = 'orientação inválida, deve ser "N", "S", "E" or "W"', -- 'invalid direction should be "N", "S", "E" or "O"',
invalidNS = 'orientação de latitude inválida, deve ser "N" ou "S"', -- 'could not find latitude direction (should be N or S)',
invalidEW = 'orientação de longitude inválida, deve ser "E" ou "W"', -- 'could not find longitude direction (should be W or E) ',
noCardinalDirection = 'orientação cardinal não informada', -- 'no cardinal direction found in coordinates',
invalidDirection = 'direção inválida', -- 'invalid direction',
latitude90 = 'latitude > 90',
longitude360 = 'longitude > 360',
minSec60 = 'minutos ou segundos > 60',
negativeCoode = 'em formato dms os graus devem ser positivos', -- 'dms coordinates should be positive',
dmIntergers = 'graus e minutos devem ser números inteiros', -- 'degrees and minutes should be integers',
tooManyParam = 'muitos parâmetros para latitude ou longitude', -- 'too many parameters for coordinates',
coordMissing = 'latitude ou longitude ausente', -- 'latitude or longitude missing',
invalidGlobe = 'globo inválido : ', -- 'invalid globe:',
}
local coordParse = {
NORTH = 'N',
NORTE = 'N',
EAST = 'E',
LESTE = 'E',
L = 'E',
WEST = 'W',
W = 'W',
O = 'W',
OESTE = 'W',
SOUTH = 'S',
SUL = 'S',
}
--Ajuda:Function_genre (gênero)
local genre = {
ms = {le="a ", du="do ", de="de ", ao="ao ", em="em "},
msa = {le="a ", du="da ", de="de", ao="à ", em="em "},
msi = {le="", du="do ", de="de ", ao="à ", em="à "},
msia = {le="", du="do ", de="de ", ao="à ", em="à "},
msiae = {le="", du="do ", de="de ", ao="à ", em="em "},
fs = {le="a ", du="da ", de="de ", ao="à ",em="em "},
fsa = {le="a ", du="da ", de="de ", ao="à ", em="em "},
fsi = {le="", du="de ", de="de ", ao="à ", em="à "},
fsia = {le="", du="da ", de="de ", ao="à ", em="à "},
mp = {le="os ", du="dos ", de="dos ", ao="aos ", en="em "},
fp = {le="as ", du="das ", de="das ", ao="as ", em="em "}
}
local globedata = {
--[[ notes:
radius in kilometers (especially imprecise for non spheric bodies)
defaultdisplay is currently disabled, activate it ?
]]--
ariel = {radius = 580, defaultdisplay = 'dec east' },
callisto = {radius = 2410, defaultdisplay = 'dec west' },
ceres = {radius = 470, defaultdisplay = 'dec east' },
charon = {radius = 1214, defaultdisplay = 'dec east' },
deimos = {radius = 7, defaultdisplay = 'dec west' },
dione = {radius = 560, defaultdisplay = 'dec west' },
enceladus = {radius = 255, defaultdisplay = 'dec west' },
ganymede = {radius = 2634, defaultdisplay = 'dec west' },
earth = {radius = 6371, defaultdisplay = 'dms' },
europa = {radius = 1561, defaultdisplay = 'dec east' },
hyperion = {radius = 140, defaultdisplay = 'dec west' },
iapetus = {radius = 725, defaultdisplay = 'dec west' },
['io'] = {radius = 1322, defaultdisplay = 'dec west' },
jupiter = {radius = 68911, defaultdisplay = 'dec east' },
mars = {radius = 3389.5, defaultdisplay = 'dec east' },
mercury = {radius = 2439.7, defaultdisplay = 'dec west' },
mimas = {radius = 197, defaultdisplay = 'dec west' },
miranda = {radius = 335, defaultdisplay = 'dec east' },
moon = {radius = 1736, defaultdisplay = 'dec' },
neptune = {radius = 24553, defaultdisplay = 'dec east' },
oberon = {radius = 761, defaultdisplay = 'dec east' },
phoebe = {radius = 110, defaultdisplay = 'dec west' },
phobos = {radius = 11, defaultdisplay = 'dec west' },
pluto = {radius = 1185, defaultdisplay = 'dec east' },
rhea = {radius = 765, defaultdisplay = 'dec west' },
saturn = {radius = 58232, defaultdisplay = 'dec east' },
titan = {radius = 2575.5, defaultdisplay = 'dec west' },
tethys = {radius = 530, defaultdisplay = 'dec west' },
titania = {radius = 394, defaultdisplay = 'dec east' },
triton = {radius = 1353, defaultdisplay = 'dec east' },
umbriel = {radius = 584, defaultdisplay = 'dec east' },
uranus = {radius = 25266, defaultdisplay = 'dec east' },
venus = {radius = 6051.8, defaultdisplay = 'dec east' },
vesta = {radius = 260, defaultdisplay = 'dec east' }
}
globedata[''] = globedata.earth
local wikidatathreshold = 10 -- Se a distância entre as coordenadas Wikipedia e Wikidata exceder o limite (em quilômetros), uma categoria de manutenção será adicionada
local lang = mw.language.getContentLanguage()
local default_zoom = 13
local function makecat(cat, sortkey)
if type( sortkey ) == 'string' then
return '[[Category:' .. cat .. '|' .. sortkey .. ']]'
else
return '[[Category:' .. cat .. ']]'
end
end
----------------------------------------
--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
* D: more than one primary coord
]]--
local errorstring = ''
local function makeerror(args)
local errormessage = ''
if args.message then
errormessage = '<strong class="error"> Coordenadas : ' .. 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
local function showerrors()
return errorstring
end
-- Distance computation
function p._distance(a, b, globe) -- calcula a [[distância orthodromique]] em quilóimetros entre dois pontos do globo
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('coordenadas não informadas, não consegue calcular a distância')
end
if type(latA) ~= 'number' or type(latB) ~= 'number' or type(longA) ~= 'number' or type(longB) ~= 'number' then
error('coordenadas não são numéricas, não consegue calcular a distância')
end
if not globe or not globedata[globe] then
return error('globe: ' .. globe .. 'não é suportado')
end
-- calcular a distância angular em radians
local convratio = math.pi / 180 -- converter em radians
latA, latB, longA, longB = convratio * latA, convratio * latB, convratio * longA, convratio * longB
local cosangle = math.sin(latA) * math.sin(latB) + math.cos(latA) * math.cos(latB) * math.cos(longB - longA)
if cosangle >= 1 then -- may be above one because of rounding errors
return 0
end
local angle = math.acos(cosangle)
-- calcular a distância em km
local 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
local function geoHackUrl(decLat, decLong, globe, displayformat, objectname, extraparams)
extraparams = extraparams or ''
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'
elseif globedata[globe].defaultdisplay == 'dec west' then
geohacklongitude = decLong .. '_W'
else
geohacklongitude = decLong .. '_E'
end
-- prepares the 'paramss=' parameter
local geohackparams = geohacklatitude .. '_' .. geohacklongitude .. '_' ..extraparams
-- concatenate parameteres for geohack
return i18n.geohackurl ..
"&pagename=" .. mw.uri.encode(mw.title.getCurrentTitle().prefixedText, "WIKI") ..
"¶ms=" .. geohackparams ..
(objectname and ("&title=" .. mw.uri.encode(objectname)) or "")
end
--HTML builder for a geohack link
local function buildHTML(decLat, decLong, dmsLat, dmsLong, globe, displayformat, displayinline, displaytitle, objectname, extraparams)
-- 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 )
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
local function buildMaplinkHTML( decLat, decLong, dmsLat, dmsLong, globe, displayformat, displayinline, displaytitle, 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
-- 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
-- adicionar a 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{
name = 'maplink',
content = mw.text.jsonEncode( jsonParams ),
args = {
text = displaycoords[1] .. ", " .. displaycoords[2],
zoom = zoom( extraparams ) or default_zoom,
latitude = decLat,
longitude = decLong,
}
}
-- format result depending on args["display"] (nil, "inline", "title", "inline,title")
local inlineText = displayinline and maplink or ''
local titleText = ''
if displaytitle then
local htmlTitle = mw.html.create('span')
:attr{ id = 'coordinates' }
:addClass( displayinline and 'noprint' or nil )
:wikitext( maplink )
local frame = mw.getCurrentFrame()
titleText = frame:extensionTag( 'indicator', tostring(htmlTitle), { name = 'coordinates' } )
end
return inlineText .. titleText
end
-- dms specific funcions
local function twoDigit( value )
if ( value < 10 ) then
value = '0' .. lang:formatNum( value )
else
value = lang:formatNum( value )
end
return value
end
function p.displaydmsdimension(valuetable, format) -- formato em latitude ou 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 = lang:formatNum( valuetable.degrees ) .. i18n.degrees
if valuetable.minutes then
minutes = twoDigit( valuetable.minutes ) .. i18n.minutes
end
if valuetable.seconds then
seconds = twoDigit( valuetable.seconds ) .. i18n.seconds
end
return degrees .. minutes .. seconds .. direction
end
local 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 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
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)
-- no error checking, done in function validdms
local dimensionobject = {}
-- direction and dimension (= latitude or longitude)
dimensionobject.direction = direction
if dimension then
dimensionobject.dimension = dimension
elseif direction == 'N' or direction == 'S' then
dimensionobject.dimension = 'latitude'
elseif direction == 'E' or direction == 'W' then
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._parsedmsstring( str, dimension ) -- pega uma sequência e dá nomes aos parâmetros
-- output table: { latitude=, longitude = , direction = }
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
--- decimal specific functions
function p.displaydec(latitude, longitude, 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
local function parsedec(dec, coordtype, globe) -- coordtype = latitude or longitude
dec = mw.text.trim(dec)
if not dec then
return nil
end
if coordtype ~= 'latitude' and coordtype ~= 'longitude' then
makeerror({'invalid coord type', sortkey = "A"})
return nil
end
local numdec = tonumber(dec) -- numeric value, kept separated as it looses significant zeros
if not numdec then -- tries the decimal + direction format
dec = mw.ustring.gsub( mw.ustring.upper( dec ), '%a+', coordParse )
local direction = mw.ustring.sub(dec, mw.ustring.len(dec), mw.ustring.len(dec))
dec = mw.ustring.sub(dec, 1, mw.ustring.len(dec)-2) -- removes the /N at the end
if not dec or not tonumber(dec) then
return nil
end
if direction == 'N' or direction == 'E' or direction == 'W' and globedata[globe].defaultdisplay == 'dec west' then
numdec = tonumber( dec )
elseif direction == 'W' or direction == 'S' then
dec = '-' .. dec
numdec = tonumber( 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
makeerror({message = i18n.latitude90 , sortkey = 'A'})
return nil
end
if coordtype == 'longitude' and math.abs(numdec) > 360 then
makeerror({message = i18n.longitude360 , sortkey = 'A'})
return nil
end
return dec
end
-- dms/dec conversion functions
local function convertprecision(precision) -- converts a decimal precision like "2" into "dm"
if precision >= 3 then
return 'dms'
elseif precision >=1 then
return 'dm'
else
return 'd'
end
end
local function determinedmsprec(decs) -- returns the most precision for a dec2dms conversion, depending on the most precise value in the decs table
local precision = 0
for d, val in ipairs(decs) do
precision = math.max(precision, math_mod._precision(val))
end
return convertprecision(precision)
end
local function dec2dms_d(dec)
local degrees = math_mod._round( dec, 0 )
return degrees
end
local function dec2dms_dm(dec)
dec = math_mod._round( dec * 60, 0 )
local minutes = dec % 60
dec = math.floor( (dec - minutes) / 60 )
local degrees = dec % 360
return degrees, minutes
end
local function dec2dms_dms(dec)
dec = math_mod._round( dec * 60 * 60, 0 )
local seconds = dec % 60
dec = math.floor( (dec - seconds) / 60 )
local minutes = dec % 60
dec = math.floor( (dec - minutes) / 60 )
local degrees = dec % 360
return degrees, minutes, seconds
end
function p._dec2dms(dec, coordtype, precision, globe) -- coordtype: latitude or longitude
local degrees, minutes, seconds
-- verificação do globo
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) -- as coordenadas em dms são sempre positivas
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 == 'norte' then
coordtype = 'latitude'
else
coordtype = 'longitude'
end
if dirpositive == 'norte' or dirpositive == 'leste' or dirnegative == 'oeste' or dirnegative == 'sul' 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) -- transformar uma tabela de minutos de segundo em um número decimal
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 -- verifique a precisão dos dados iniciais
precision = 5 + math.max( math_mod._precision(tostring(seconds), 0 ) ) -- passagem por cadeias de texto bastante complicada?
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] -- coordenadas já em decimal
elseif not args[2] then
local dmsobject = p._parsedmsstring(args[1])
if dmsobject then
return p._dms2dec(dmsobject) -- coordena sob a proa 23/22/N
else
local coordType
if args[1]:match( '[NS]' ) then
coordType = 'latitude'
elseif args[1]:match( '[EWO]') then
coordType = 'longitude'
end
if coordType then
local result = parsedec( args[1], coordType, args.globe or 'earth' )
if result then
return result
end
end
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('Módulo:Infobox/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:Infobox/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)
local entitycat = mw.wikibase.getEntity()
local basecat = '!Páginas com mapas'
local finalcat = {}
--BADGES
if entitycat then
--BADGES
for i, badgeId in ipairs( entitycat.sitelinks['ptwiki'].badges ) do
if badgeId == 'Q17437796' then
basecat= string.gsub(basecat, "!Páginas com mapas", "!Artigos por qualidade sobre geografia")
end
if badgeId == 'Q17437798' then
basecat= string.gsub(basecat, "!Páginas com mapas", "!Artigos bons sobre geografia")
end
end
end
table.insert(finalcat,basecat)
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 -- não adicione nada aqui para que a chamada para esta função retorne nil na ausência de dados
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 -- não há problema se o globo é duplicado
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
--Recuperação dos 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) -- parses 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 para infobox, a depreciar
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 para infobox, a depreciar
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
--[[
link
Simple function to export the coordinates link for other uses.
Usage:
{{#invoke:Coordenadas | link }}
]]
function p.link(frame)
return coord_link;
end
return p