Modulo:Mappa di localizzazione corpo celeste

Modulo che implementa il template {{Mappa di localizzazione corpo celeste}}.

Ha una sottopagina di configurazione: Modulo:Mappa di localizzazione corpo celeste/Configurazione.


--[[
* Modulo che implementa il template Mappa di localizzazione corpo celeste.
]]--

require('strict')

local getArgs = require('Modulo:Arguments').getArgs
local mWikidata = require('Modulo:Wikidata')
local cfg = mw.loadData('Modulo:Mappa di localizzazione corpo celeste/Configurazione')
local errorCategory = '[[Categoria:Voci con errori del modulo Mappa di localizzazione corpo celeste]]'

-- Error handler per xpcall, formatta l'errore.
--
-- @param {string} msg
-- @return {string}
local function errhandler(msg)
	local cat = mw.title.getCurrentTitle().namespace == 0 and errorCategory or ''
	return string.format('<span class="error">%s</span>%s', msg, cat)
end

-- Restituisce l'offset in pixel dal margine sinistro di un punto su una certa mappa,
-- in base alla sua longitudine e alla larghezza del marker.
-- Le funzioni getX e getY sono state convertite da:
-- Template:SovraImmagineAstronomia/proiez equirettangolare
-- Template:SovraImmagineAstronomia/proiez cilindrica centrografica di Mercatore
-- Template:SovraImmagineAstronomia/proiez cilindrica equivalente di Lambert
--
-- @param {table} map
-- @param {number} long
-- @param {number} marksize
-- @return {number}
local function getX(map, long, marksize)
	local dim = 250
	return math.floor(dim * (math.fmod(long + 360 + map.spost_mer0, 360) / 360) - marksize / 2)
end

-- Restituisce l'offset in pixel dal margine superiore di un punto su una certa mappa,
-- in base alla sua latitudine e all'altezza del marker.
--
-- @param {table} map
-- @param {number} lat
-- @param {number} marksize
-- @return {number}
local function getY(map, lat, marksize)
	local dim = 250
	local ret = 0
	if map.projection == 'equirettangolare' then
		-- Proiezione equirettangolare
		ret = (dim * map.height / map.width) / 2 *
			  (-lat / map.max_lat) +
			  (dim * map.height / map.width) / 2 - marksize / 2
	elseif map.projection == 'Mercatore' then
		-- Proiezione cilindrica centrografica di Mercatore
		ret = (dim * map.height / map.width) / 2 *
			  (-math.log(math.tan(math.pi / 4 + lat * math.pi / 360))) /
			  math.log(math.tan(math.pi / 4 + map.max_lat * math.pi / 360)) +
			  (dim * map.height / map.width) / 2 - marksize / 2
	elseif map.projection == 'Lambert' then
		-- Proiezione cilindrica equivalente di Lambert
		ret = (dim * map.height / map.width) / 2 *
			  (-math.sin(lat * math.pi / 180) / math.sin(map.max_lat * math.pi / 180)) +
			  (dim * map.height / map.width) / 2 - marksize / 2
	end
	return math.floor(ret)
end

-- =============================================================================
--                            Funzioni esportate
-- =============================================================================

local p = {}

-- Funzione di utilità per il manuale, restituisce l'elenco dei codici delle mappe configurate.
function p.maps()
	local sortedMaps = {}
	for key, _ in pairs(cfg.mappe) do
		table.insert(sortedMaps, key)
	end
	table.sort(sortedMaps)
	return mw.text.listToText(sortedMaps)
end

-- Restituisce 1 se la mappa specificata è disponibile altrimenti nil.
function p.hasmap(frame)
	local mappa = frame.args[1] and mw.ustring.lower(frame.args[1])
	return (cfg.alias[mappa] or cfg.mappe[mappa]) and 1
end

-- Funzione per l'utilizzo da altro modulo.
function p._main(args)
	-- i parametri obbligatori sono: mappa, lat e long
	if args.mappa then
		args.mappa = mw.ustring.lower(args.mappa)
	else
		error('mappa non specificata', 2)
	end
	-- eventuale alias
	args.mappa = cfg.alias[args.mappa] or args.mappa
	if not cfg.mappe[args.mappa] then
		error('mappa non disponibile: ' .. args.mappa, 2)
	end	
	-- latitudine e longitudine da Wikidata se assenti (disabilitato)
	-- args.lat = args.lat or mWikidata._getProperty( { 'P625', coord = 'latitude', n = 1 } )
	-- args.long = args.long or mWikidata._getProperty( { 'P625', coord = 'longitude', n = 1 } )
	if not args.lat then
		error('latitudine non specificata', 2)
	elseif not tonumber(args.lat) then
		error('la latitudine non è un numero', 2)
	elseif not args.long then
		error('longitudine non specificata', 2)
	elseif not tonumber(args.long) then
		error('la longitudine non è un numero', 2)
	end

	local map = cfg.mappe[args.mappa]
	local caption = string.format('Mappa topografica %s %s. Proiezione %s%s. Area rappresentata: %s.',
						args.mappa == 'luna' and 'della' or 'di',
						mw.language.getContentLanguage():ucfirst(args.mappa),
						map.projection == 'equirettangolare' and '' or 'di ', map.projection,
						map.range)

	return mw.getCurrentFrame():expandTemplate {
		title = 'Sovraimmagine',
		args = {
			sotto = map.image,
			sotto_larghezza = '250px',
			sotto_didascalia = caption,
			sopra = args.mark or 'DeepPink pog.svg',
			sopra_larghezza = (args.marksize or 15) .. 'px',
			sopra_didascalia = args.nome or '',
			x = getX(map, args.long, args.marksize or 15),
			y = getY(map, args.lat, args.marksize or 15)
		}
	}
end

-- Funzione per il template {{Mappa di localizzazione corpo celeste}}.
function p.main(frame)
	return select(2, xpcall(function()
		return p._main(getArgs(frame, {parentOnly = true}))
	end, errhandler))
end

return p