Esta wiki foi não teve nenhuma edição nem entrada nos registos durante os últimos 45 dias e foi marcada automaticamente como inativa. Se quiser impedir a wiki de ser fechada mostre alguns sinais de atividade. Se não houver sinais de utilização da wiki nos próximos 15 dias, ela será fechada de acordo com as normas de dormência (que todos os fundadores de wikis aceitam ao pedir uma wiki). Se a wiki for fechada e ninguém a reabrir nos próximos 135 dias, ela será candidata para eliminação. Nota: se é burocrata da wiki, pode ir a Special:ManageWiki e desmarcar "inativa" por si próprio.
De Família Corsi
Ir para navegação Ir para pesquisar

Descrição[editar]

Este módulo implementa a predefinição {{Coor dms}}. Por favor consulte a predefinição para mais instruções.

Uso[editar]

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 .. '&params='
--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 no Wikidata',
    notaswikidata = '!Páginas com coordenadas diferentes no Wikidata',
    nowikidata = '!Artigos com coordenadas por transcrever a 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") ..
        "&params=" .. 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 = lang:formatNum( -latitude )
        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

--[[
coord2text

(documentação a traduzir)
]]
	function p.coord2text(frame)
	if frame.args[1] == '' or frame.args[2] == '' or not frame.args[2] then return nil end
	frame.args[2] = mw.text.trim(frame.args[2])
	if frame.args[2] == 'lat' or frame.args[2] == 'long' then
		local result, negative = mw.text.split((mw.ustring.match(frame.args[1],'[%.%d]+°[NS] [%.%d]+°[EW]') or ''), ' ')
		if frame.args[2] == 'lat' then
			result, negative = result[1], 'S'
		else
			result, negative = result[2], 'W'
		end
		result = mw.text.split(result, '°')
		if result[2] == negative then result[1] = '-'..result[1] end
		return result[1]
	else
		return mw.ustring.match(frame.args[1], 'params=.-_'..frame.args[2]..':(.-)[ _]')
	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
Cookies nos ajudam a entregar nossos serviços. Ao usar nossos serviços, você concorda com o uso de cookies.