Questo modulo è utilizzato dal template {{Maplink}} per il calcolo del centro della mappa e della scala.

È utilizzata la proiezione Web Mercator (EPSG:3857).

zoom
calcola l'ingrandimento adeguato sulla base delle dimensioni dell'immagine e delle coordinate inserite.
La funzione utilizza quattro parametri obbligatori:
  • larghezza in pixel della carta (al momento non utilizzata)
  • altezza in pixel della carta (al momento non utilizzata)
  • lista separata da virgole con la longitudine dei singoli punti (x1,x2,x3,...)
  • lista separata da virgole con la latitudine dei singoli punti (y1,y2,y3,...)
centro_lon
calcola la longitudine del punto medio rispetto al valore minimo e a quello massimo tra quelli inseriti.
La funzione utilizza un solo parametro:
  • lista separata da virgole con la longitudine dei singoli punti (x1,x2,x3,...)
centro_lat
calcola la latitudine del punto medio rispetto al valore minimo e a quello massimo tra quelli inseriti (utilizza una correzione dovuta alla proiezione utilizzata da OpenStreetMap).
La funzione utilizza un solo parametro:
  • lista separata da virgole con la latitudine dei singoli punti (y1,y2,y3,...)

require('Module:No globals')
local getArgs = require('Module:Arguments').getArgs
local numLeg = require('Module:Overlay').icon

local p = {}
local pp = {}
local txt = {}

local function agg(t,...)
    local args = {...}
    for _, s in ipairs(args) do
        table.insert(t, s)
    end
end

function p.mappa(frame)
	local t = getArgs(frame)

	local err = '-'

	local cornice
	if (t['cornice']) then cornice = tonumber(t['cornice']) or 1 else cornice = 1 end
	local allinea = t['allinea'] or 'right'
	local dida    = t['didascalia'] or ''
	local elenco  = t['mostra elenco'] or 0
	local largh   = t['larghezza'] or 350
	local altezza = t['altezza'] or 300
	local gruppo  = t['gruppo'] or ''
	if not (gruppo == '') then gruppo = '-'..gruppo end
	local zoom    = tonumber(t['zoom']) or '-1'
	local centrox = t['centro_lon'] or ''
	local centroy = t['centro_lat'] or ''
	local colore  = t['colore'] or '#b80000'

	local lat1, lat2, lon1, lon2 = 400, -400, 400, -400

	local num = 1
	while (t['nome'..num]) do
		pp[num] = {
			nome = t['nome'..num],
			lat  = tonumber(t['lat'..num]) or -400,
			lon  = tonumber(t['lon'..num]) or -400,
			col  = t['colore'..num] or colore,
			num  = t['numero'..num] or num
		}
		if (pp[num].lat > 85 or pp[num].lat<-85) then
			err = string.format('latitudine non valida per il punto %d', num)
		elseif (pp[num].lon > 180 or pp[num].lon<-180) then
			err = string.format('longitudine non valida per il punto %d', num)
		else
			lat1 = math.min(lat1, pp[num].lat)
			lat2 = math.max(lat2, pp[num].lat)
			lon1 = math.min(lon1, pp[num].lon)
			lon2 = math.max(lon2, pp[num].lon)
		end
		num = num + 1
	end

	if (err == '-') then
		if (centrox == '') then centrox = (lon1+lon2)/2 end
		if (centroy == '') then
			local l1 = 1-math.log(math.tan( math.pi*(1 + lat1/90)/4))/math.pi
			local l2 = 1-math.log(math.tan( math.pi*(1 + lat2/90)/4))/math.pi
			centroy = (l1+l2)/2
			centroy = (math.atan(math.exp(math.pi*(1-centroy)))-math.pi/4)*360/math.pi
		end
		if (zoom == '-1') then
			local dx = 1.1*(lon2-lon1)/360
			local dy = 1.1*(math.log(math.tan( math.pi*(1 + lat2/90)/4)) - math.log(math.tan( math.pi*(1 + lat1/90)/4)))/(2*math.pi)

			local scalax, scalay
			if (dx == 0) then scalax = 18 else scalax = math.floor(-math.log(dx)/math.log(2)) end
			if (dy == 0) then scalay = 18 else scalay = math.floor(-math.log(dy)/math.log(2)) end
			if ((dx == 0) and (dy == 0)) then
				zoom = 10 --valore default per singolo punto
   			else
   				zoom = math.max(0,math.min(18,scalax, scalay))
			end
		end
		if (zoom < 0) then zoom = 0 elseif (zoom>18) then zoom = 18 end
		if (cornice == 1) then
			agg(txt,'\n{| class="wikitable')
			if (allinea == 'right') then agg(txt,' floatright') elseif (allinea == 'left') then agg(txt,' foatleft') end
			agg(txt,'" style="border: 1px solid darkgray;')
			if (allinea == 'center') then agg(txt,'margin-left: auto; margin-right: auto') end
			agg(txt,'"\n|-\n|style="width: ',largh,'px;"|')
		end
		-- grafico
		local gr1 = {}
		if (math.abs(centroy)<20) then
			gr1 = {'10 000km','5000km','3000km','1500km','1000km','400km','200km','100km','60km','20km','10km','6km','4km','2km','1km','400m','200m','100m','60m' }
		elseif (math.abs(centroy)<40) then
			gr1 = {'10 000km','5000km','3000km','1200km','800km','300km','150km','75km','45km','15km','8km','5km','3km','1.5km','750m','300m','150m','75m','45m' }
		elseif (math.abs(centroy)<40) then
			gr1 = {'10 000km','5000km','3000km','1000km','500km','200km','100km','50km','30km','10km','5km','3km','2km','1km','500m','200m','100m','50m','30m' }
		else
			gr1 = {'10 000km','5000km','3000km','900km','400km','160km','80km','40km','20km','7km','4km','2km','1km','600m','350m','160m','80m','40m','20m' }
		end
		local gr2 = { '{"lat":', centroy, ',"lon":', centrox, ',"img":"wikirawupload:',frame:preprocess('{{filepath:Mapscaleline.svg|120}}'),'","width":50,"height":8,"offsetX":', (math.floor(largh/2)-37),
		    ',"offsetY": ',(math.floor(altezza/2)-10),',"textAlign":"right","textDx":22,"textDy":-2,"textColor": "grey","textFont":"Tahoma","textFontSize":9,"text": "',
			gr1[zoom+1],'" }' }
		for i=1,#pp do
			agg(gr2,',{"lat":',pp[i].lat,',"lon":',pp[i].lon,',"size":"200","color":"',pp[i].col,'","strokeColor":"","shape":"circle","text":"","textAlign":"left","textBaseline":"middle","textDx":0,"textDy":1,"textFontSize":10},{"lat":',pp[i].lat,',"lon":',pp[i].lon,',"shape":"square","size": "0","text":"',pp[i].num,'","textAlign":"center","textBaseline":"bottom","textDx":0,"textDy":5.5,"textFont":"Arial","textFontSize": 11,"textFontWeight":"bold","textColor":"white"}')
		end
		agg(txt, mw.getCurrentFrame():expandTemplate { title = "Graph:Street map with marks",
			args = { lat = centroy, lon = centrox, zoom = zoom, width = largh, height = altezza, minimap = 0, table.concat(gr2) }
		} )
		agg(txt,'<div style="text-align:left;font-size:70%;color:grey"><span style="font-size:125%">')
		-- maplink
		local ml = {}
		agg(ml,'<maplink zoom="',zoom,'" latitude="',centroy,'" longitude="',centrox,'" text="[Schermo intero]">[ {"type": "FeatureCollection", "features": [')
		for i=1,#pp do
			if (i>1) then agg(ml,',') end
			agg(ml,'{"type":"Feature","geometry":{"type":"Point","coordinates":[',pp[i].lon,',',pp[i].lat,'] }')
			agg(ml,',"properties":{"title": "',pp[i].nome,'","description":"","marker-symbol": "-number',gruppo,'","marker-size":"medium","marker-color":"',pp[i].col,'" } }')
		end
		agg(ml,'] } ]</maplink>')
		agg(txt, frame:preprocess( table.concat(ml)))
		agg(txt,'</span><div style="float:right" class="plainlinks nourlexpansion">[https://wikimediafoundation.org/wiki/Maps_Terms_of_Use Wikimedia] | © [https://www.openstreetmap.org/copyright OSM]</div></div>')

		if (cornice == 1) then
			agg(txt,'\n|-')
			if not (dida == '') then agg(txt,'\n|style="font-size:90%"|',dida) end
			if (elenco == '2') then
				if (dida == '') then agg(txt,'\n|') end
				agg(txt,'\n{| width="100%"\n|-\n|width=50% valign=top|<small>')
				for i=1,#pp do
					agg(txt,numLeg({  ['1'] = pp[i].num, ['2'] = pp[i].col}),' ',pp[i].nome,'<br/>')
					if (i == math.floor(#pp/2 +0.5)) then agg(txt,'</small>\n|width=50% valign=top|<small>') end
				end
				agg(txt,'</small>\n|}')
			elseif (elenco == '1') then
				if (dida == '') then agg(txt,'\n|style="font-size:90%"|') else agg(txt,'<br/>') end
				agg(txt,'<small>')
				for i=1,#pp do
					agg(txt,numLeg({  ['1'] = pp[i].num, ['2'] = pp[i].col}),' ',pp[i].nome,'<br/>')
				end
				agg(txt,'</small>')
			end
			agg(txt,'\n|}')
		end
		return (table.concat(txt))
	else
		return err
	end
end


-- Calcola centro per longitudine
-- esempio chiamata di funzione {{#invoke:Mappa OSM|centro_lon|x1,x2,...}}
function p.centro_lon(frame)
	local t = getArgs(frame)
	local mn, mx = 400, -400
	local xval
	for x in string.gmatch(t[1],'([^,]+)') do
		xval = tonumber(x)
		if (mn > xval) then mn = xval end
		if (mx < xval) then mx = xval end
	end
    return (mn+mx)/2
end

-- Calcola centro per latitudine
-- esempio chiamata di funzione {{#invoke:Mappa OSM|centro_lat|x1,x2,...}}
function p.centro_lat(frame)
	local t = getArgs(frame)
	local mn, mx = 400, -400
	local xval
	for x in string.gmatch(t[1],'([^,]+)') do
		xval = tonumber(x)
		if (mn > xval) then mn = xval end
		if (mx < xval) then mx = xval end
	end
	if ((mx>85) or (mn<-85)) then return 0 end
	local lat1 = 1-math.log(math.tan( math.pi*(1 + mn/90)/4))/math.pi
	local lat2 = 1-math.log(math.tan( math.pi*(1 + mx/90)/4))/math.pi
	local latm = (lat1+lat2)/2
	local coord = (math.atan(math.exp(math.pi*(1-latm)))-math.pi/4)*360/math.pi
    return coord
end

-- Calcola la scala adeguata per mappa OSM
-- esempio chiamata di funzione {{#invoke:Mappa OSM|zoom|w|h|x1,x2,...|y1,y2...}}
function p.zoom(frame)
	local t = getArgs(frame)
	local lat1, lat2, lon1, lon2 = 400, -400, 400, -400
	local dimx = tonumber(t[1]) or 1 --larghezza
	local dimy = tonumber(t[2]) or 1 --altezza
	local vlr
	for x in string.gmatch(t[3],'([^,]+)') do
		vlr = tonumber(x)
		if (lon1 > vlr) then lon1 = vlr end
		if (lon2 < vlr) then lon2 = vlr end
	end
	for x in string.gmatch(t[4],'([^,]+)') do
		vlr = tonumber(x)
		if (lat1 > vlr) then lat1 = vlr end
		if (lat2 < vlr) then lat2 = vlr end
	end

	-- problemi con latitudine oltre 85°
	if ((lat2>85) or (lat1<-85)) then return 0 end

	-- calcola posizione rispetto a Web Mercator per griglia di lato 1
	-- con fattore 1.1 per evitare punti troppo vicini al margine
	local dx = 1.1*(lon2-lon1)/360
	local dy = 1.1*(math.log(math.tan( math.pi*(1 + lat2/90)/4)) - math.log(math.tan( math.pi*(1 + lat1/90)/4)))/(2*math.pi)

	-- calcolo scale per coordinate
	local scalax, scalay
	if (dx == 0) then scalax = 18 else scalax = math.floor(-math.log(dx)/math.log(2)) end
	if (dy == 0) then scalay = 18 else scalay = math.floor(-math.log(dy)/math.log(2)) end
	local scala
    if ((dx == 0) and (dy == 0)) then
    	scala = 10 --valore default per singolo punto
   	else
   		scala = math.max(0,math.min(18,scalax, scalay)) --calcolo scala minima compresa tra 0 e 18
   	end
	return scala
end

-- Calcola gradi decimali
-- esempio chiamata di funzione {{#invoke:Mappa OSM|gradi|numero gradi|numero primi|numero secondi|punto cardinale}}
function p.gradi(frame)
	local t = getArgs(frame)
	local t1 = tonumber(t[1]) or 0
	local t2 = tonumber(t[2]) or 0
	local t3 = tonumber(t[3]) or 0
	local s = 1;
	if ((t[4] == 'S') or (t[4] == 'W')) then s = -1 end
	return (s*(t1+t2/60+t3/3600))
end

return p