Module:Carte : Différence entre versions

De Lagny-sur-Marne Wiki
Aller à : navigation, rechercher
(affinage)
Ligne 177 : Ligne 177 :
 
local data = require('Module:Carte/données')
 
local data = require('Module:Carte/données')
 
local validmaps = {}
 
local validmaps = {}
local lat, long = tonumber(params.latitude), tonumber(params.longitude)
+
local lat = tonumber(params.latitude) or tonumber(coord.dms2dec({args={params.latitude}}))
 +
local long = tonumber(params.longitude) or tonumber(coord.dms2dec({args={params.longitude}}))
 
if not lat or not long then return nil end
 
if not lat or not long then return nil end
 
for i, map in pairs(data) do
 
for i, map in pairs(data) do
Ligne 199 : Ligne 200 :
  
 
local chosenmaps = {} -- on ne les gardes pas toutes, ça serait souvent trop
 
local chosenmaps = {} -- on ne les gardes pas toutes, ça serait souvent trop
+
 
local function addmap(map)
+
local havezone = {} -- paramètre "zone" des carte déjà obtenu, pour ne pas avoir le même deux fois: { zone = {nom de la carte, position de la carte} }
return table.insert(chosenmaps, map.name)
+
 
 +
local forbiddenzones = { -- zone peu utiles, à ne pas utiliser par défaut
 +
['future région française'] = true
 +
}
 +
 
 +
local function addmap(map, pos) -- ajoute la carte à la liste et enregistre qu'elle a une carte avec ce paramètre "zone"
 +
if pos then
 +
chosenmaps[pos] = map.name
 +
havezone[map.zone] = {map, pos}
 +
else
 +
table.insert(chosenmaps, map.name)
 +
havezone[map.zone] = {map, #chosenmaps}
 +
end
 +
end
 +
local function centrality(map)
 +
-- retourne un indice ah hoc de centralité, plus faible si le point est près d'un bord
 +
local function compute(point, end1, end2)
 +
local pct = (point - end1) / (end2- end1)
 +
return 0.5 - math.abs(0.5 - pct)
 +
end
 +
local latcentrality = compute(lat, map.top, map.bottom)
 +
local longcentrality = compute(long, map.left, map.right)
 +
return math.min(latcentrality, longcentrality)
 
end
 
end
 
local havezone = {} -- paramètre "zone" des carte déjà obtenu, pour ne pas avoir le même deux fois
 
  
 
for i, map in pairs(validmaps) do
 
for i, map in pairs(validmaps) do
if #chosenmaps > 2 then -- 3 au maximum
+
if not(havezone[map.zone]) and  (not forbiddenzones[map.zone]) and #chosenmaps < 3 then
break
 
end
 
if not(havezone[map.zone]) then -- sinon, il faudrait peut-être essayer de trouver la plus centrée
 
 
addmap(map)
 
addmap(map)
 
end
 
end
if map.zone then
+
if map.zone and havezone[map.zone] and (centrality(map) > centrality(havezone[map.zone][1] ))  then -- si deux cartes ont le même paramètre "zone", on prend la mieux centrée
havezone[map.zone] = true
+
addmap(map, havezone[map.zone][2])
 
end
 
end
 
end
 
end

Version du 9 mars 2015 à 15:45

La documentation pour ce module peut être créée à Module:Carte/doc

local p = {}
local pointmod = require('Module:Carte/Points')
local linguistic = require('Module:Linguistique')
local maintenance = ''
local coord  = require('Module:Coordinates')
local function loaddata(name) 
	return require('Module:Carte/données/' .. mw.ustring.lower(name))
end

local divstyle = {
	['clear'] = 'right',
	['width'] ='25em',
	['text-align'] = 'center',
	['font-size'] = '0.9em',
	['line-height'] = '1.4em',
	['margin'] = '0 0 0.5em 1em',
	['max-width'] = '325px',
	['word-wrap'] = 'break-word',
	['max-width'] = '99%',
	['height'] = 'auto',
	['justify-content'] = 'space-around',
	['align-items'] = 'center',
}

local function addmaintenancecat(cat, sortkey) -- ajoute du texte à la string maintenance en cas de problème
	if mw.title.getCurrentTitle().namespace ~= 0 then
		return
	end
	maintenance = maintenance .. '[[Category:' .. cat .. ']]'
end

-- 'Projection conique avec DL'  
local function dllat(latitude, longitude, mapdata) -- conique avec DL
	local val = 
	 	(mapdata.y0 +
	 		( mapdata.iheight/2 - mapdata.y0 ) *
	 		(1 - mapdata.t *
	 			(latitude - mapdata.centrallat) *
	 			(0.01745329252 + 0.00000177219231 * (latitude - mapdata.centrallat) ^2)
	 		)*
	 		( 1- 0.00015230871 * (longitude-mapdata.centrallong) ^2 * mapdata.s^2)
	 	) / mapdata.iheight

	return val
end
local function dllong(latitude, longitude, mapdata)
	local val = 
		( (mapdata.x0 or (mapdata.iwidth/2)) + 
			( mapdata.iheight/2 - mapdata.y0 ) *
			( 1 -mapdata.t * 
				(latitude-mapdata.centrallat) *
				( 0.01745329252 + 0.00000177219231 * (latitude-mapdata.centrallat) * (latitude-mapdata.centrallat) )
			) * 
		(longitude-mapdata.centrallong) * mapdata.s *
		(0.01745329252 - 0.000000886096156 * (longitude-(mapdata.centrallong)) * (longitude-(mapdata.centrallong))
			* mapdata.s^2
		)
	) / mapdata.iwidth
	return val 
end

--longitude équirectangulaire
local function equirecLong(longitude, mapdata)
	local left, right = mapdata.left, mapdata.right
	if right < left then -- si la carte passe le méridien 180
		right = 360 + right
		if longitude < 0 then longitude = (360 + longitude) end
	end
	return  (longitude - left) / (right - left) 
end

local function equirecLat(latitude, mapdata)
	return (latitude - mapdata.top) / (mapdata.bottom - mapdata.top) 	
end
----------------------------------
local function pointposition(latitude, longitude, mapdata)
	local latitude = tonumber(latitude) or tonumber(coord.dms2dec({args={latitude}}))
	local longitude = tonumber(longitude) or tonumber(coord.dms2dec({args={longitude}}))
		
	local ypos, xpos
	if mapdata.x and mapdata.y then -- pour les cartes complexes : calcul de la position à partir de formules en Wikicode dans les clés "x" et "y"
		xpos = mapdata.x(latitude, longitude) / 100
		ypos = mapdata.y(latitude, longitude) / 100

	elseif mapdata.projection ==  'Projection équirectangulaire' then
		ypos = equirecLat(latitude, mapdata)
		xpos =  equirecLong(longitude, mapdata)
	elseif mapdata.projection == 'Projection conique avec DL' then
		ypos = dllat(latitude, longitude, mapdata)
		xpos = dllong(latitude, longitude, mapdata)
	end
	return ypos, xpos
end

local function placepoint(mapdata, point) -- fonction d'aige pour buildmap point est une table contenant latitude, longitude, type de point...
	local ypos, xpos = pointposition(point.latitude, point.longitude, mapdata)

	if (not xpos) or (not ypos) then
		return "données de géolocalisation invalides"
	end

	if (ypos > 1.1) or (xpos) > 1.1 or (ypos < -0.1) or (xpos < -0.1) then 
		return '[[Category:Article avec une géolocalisation hors-carte]]' .. 'les coordonnées indiquées sont hors de la carte de géolocalisation demandée'
	end
	
	local pointsize = tostring(point.pointsize or '8')
	local pointtext = point.text or ''
	local pointtype = point.pointtype or 'default'
	local pointimage = pointmod[pointtype]
	if not pointimage then
		pointimage = pointmod[pointtype]
		addmaintenancecat('Page avec un modèle de point de carte non supporté')
	end

	local htmlheight = tostring(ypos * 100) .. '%'
	local htmlwidth = tostring(xpos * 100) .. '%'

	local pointdiv = mw.html.create('div')
		:css{position = 'absolute', border = 'none', top = htmlheight, left = htmlwidth}
		:tag('div')
			:css{position = 'absolute', top = '-4px', left = '-4px', ['line-height'] = '0', width = '8px'}
			:wikitext('[[Image:' .. pointimage .. '|' .. pointsize .. 'px]]')
			:tag('span') 
			:css{position = 'absolute', ['text-align'] = 'left', width = '150px'}
			:wikitext(pointtext)
			:done()
		:allDone()
			
	return pointdiv
end

local function buildmap(map, maptype, width, pointtable, caption) -- fonction d'aige pour multimap
	if map == '-' then
		return
	end
	local success, mapdata = pcall(loaddata, map)
	if not success or not mapdata.images then
		addmaintenancecat('Page avec des données de géolocalisation non supportées')
	end
	local name = mapdata.name or '?'

	-- analyse linguistique pour le texte de la carte
	local datagender = mapdata.genre or ''
	local gender = string.sub(datagender, 1, 1) -- ms = masculin-singulier, fp = féminin pluriel etc.
	local number = string.sub(datagender, 2, 2)
	local determiner = mapdata.determiner
	local ofstring = linguistic.of(name, gender, number, determiner) -- restitue "de France" ou "du Japon"

	local mapname = mapdata.name
	local file = mapdata.images[maptype] or mapdata.images['default']  or mapdata.images[1]
	if not file then
		 file = mapdata.images['default']
	end
	local alt = 'voir sur la carte ' .. ofstring

	local map = mw.html.create('div')
		:css(divstyle)
		:addClass("geobox")
		:wikitext(caption or ('Localisation sur la carte ' .. ofstring))
		:tag('table')
			:addClass('DebutCarte')
			:attr({border="0", cellspacing="0", cellpadding="0"})
			:css({margin = '0', border = 'none', padding = '0'})
				:tag('tr')
					:tag('td')
						:tag('div')
							:css({position= 'relative', margin = "auto", width = '100%', ['text-align'] = 'right' })
							:wikitext('[[File:' .. file .. '|frameless|' .. width .. 'px' .. '|' .. alt .. ']]' )
	
	for i, j in pairs(pointtable) do -- pour chque point à placer, do
		map:node(placepoint(mapdata,j))
	end
	return map:done():done():done():done()
end

local function guessmaps(params)
	local data = require('Module:Carte/données')
	local validmaps = {}
	local lat = tonumber(params.latitude) or tonumber(coord.dms2dec({args={params.latitude}}))
	local long = tonumber(params.longitude) or tonumber(coord.dms2dec({args={params.longitude}}))
	if not lat or not long then return nil end
	for i, map in pairs(data) do
		if lat < map.top and lat > map.bottom then
			if map.left > map.right  then -- correction pour les cartes passant le méridien 180
				map.right = 360 + map.right
				if long < 0 then long = 360 + long end
			end
			if (long > map.left and long < map.right) then
				table.insert(validmaps, map)
			end
		end
	end
	if #validmaps == 0 then
		return nil
	end
	local function area(map) -- fonction simple juste pour pouvoir classer apprximativement les cartes pas superficie
		return (math.abs(map.top - map.bottom)) * (math.abs(map.left- map.right)) 
	end
	table.sort(validmaps, function(a, b) return area(a) < area(b) end)

	local chosenmaps = {} -- on ne les gardes pas toutes, ça serait souvent trop

	local havezone = {} -- paramètre "zone" des carte déjà obtenu, pour ne pas avoir le même deux fois: { zone = {nom de la carte, position de la carte} }

	local forbiddenzones = { -- zone peu utiles, à ne pas utiliser par défaut
		['future région française'] = true
	}

	local function addmap(map, pos) -- ajoute la carte à la liste et enregistre qu'elle a une carte avec ce paramètre "zone"
		if pos then
			chosenmaps[pos] = map.name
			havezone[map.zone] = {map, pos} 
		else
			table.insert(chosenmaps, map.name)
			havezone[map.zone] = {map, #chosenmaps} 
		end
	end
	local function centrality(map)
		-- retourne un indice ah hoc de centralité, plus faible si le point est près d'un bord
		local function compute(point, end1, end2)
			local pct = (point - end1) / (end2- end1)
			return 0.5 - math.abs(0.5 - pct)
		end
		local latcentrality = compute(lat, map.top, map.bottom)
		local longcentrality = compute(long, map.left, map.right)
		return math.min(latcentrality, longcentrality)
	end

	for i, map in pairs(validmaps) do
		if not(havezone[map.zone]) and  (not forbiddenzones[map.zone]) and #chosenmaps < 3 then
			addmap(map)
		end
		if map.zone and havezone[map.zone] and (centrality(map) > centrality(havezone[map.zone][1] ))  then -- si deux cartes ont le même paramètre "zone", on prend la mieux centrée
			addmap(map, havezone[map.zone][2])
		end
	end

	return chosenmaps
end

function p.multimap(params)
	local maplist = params.maplist
	if not maplist then
		maplist = guessmaps(params)
	end
	if type(maplist) == 'string' then
		if maplist == 'non' or maplist == 'pas pertinent' or maplist == 'non' then
			return
		end
		maplist = mw.text.split(maplist, '/', true)
	end
	if not maplist then
		return nil
	end
	local maptype = params.maptype -- à retravailler pour quand on veut la même région, mais avec plusieurs types de carte
	local width = params.width
	local pointtable = params.pointtable
	local caption = params.caption
	if not pointtable then -- pointtable est la liste des points à placer, mais lorsqu'il n'y a qu'un seul point, on peut avoir des paramètres distinctions :  
		pointtable = {{latitude = params.latitude, longitude = params.longitude, pointtype = params.pointtype}}
	end
	-- traitement de la largeur
	if width and tonumber(width) then
		width = tonumber(width)
	else
		width = 280
	end-- si pas un nombre, erreur ?
	local div =  mw.html.create('div'):addClass('img_toogle')
	
	-- met la carte à afficher par défaut à la fin, pour qu'elle soit affichée en premier
	table.insert(maplist, maplist[1])
	table.remove(maplist, 1)
	
 	--transition: appel aux [[Modèle:Géolocalisation/]] n en l'absence de données dans le module
	for i, j in pairs(maplist) do
		if j == '' then break end
		local success, data = pcall(loaddata, j) 
		if not success then
		 	local mapliststring = ''
		 	for i, j in pairs(maplist) do
		 		mapliststring = j .. '/' .. mapliststring
		 	end
			return mw.getCurrentFrame():expandTemplate{ title = 'Infobox/Géolocalisation multiple/transition', args = {['géolocalisation'] = mapliststring, type = maptype, latitude = params.latitude, longitude = params.longitude }}
	.. '[[Catégorie:Page avec des données de géolocalisation non supportées]]'
		end
	end
	for i, j in pairs(maplist) do
		if j == '' then break end
		local newmap = buildmap( j, maptype, width, pointtable, caption)
		div:node(newmap)
	end
	return div
end

function p.map(frame)
	local args = frame.args
	-- utilisation du franaçs
	args.maplist =  mw.text.split( args.carte, '/', true)
	return p.multimap(args)
end
return p