ניתן ליצור תיעוד על היחידה הזאת בדף יחידה:מפהמפורטת/תיעוד

-- Credits: -- Original from Wikivoyage -- Developed for Kartographer version on Wikipedia by Vriullop @cawiki -- Formulae: --    CSGNetwork at http://www.csgnetwork.com/degreelenllavcalc.html via @enwiki --    OpenStreetMap -- Version: 20170813  local p = {}  -- Localization on [[Module:Map/i18n]] local i18n = { 	["coordinate-invalid"] = "פרמטר $1 הוא ערך בלתי תקין של \"רוחב,אורך\".", 	["type-invalid"] = "סוג $1 אינו תקין. השתמשו ב mapframe או ב-maplink.", 	["geotype-invalid"] = "Geotype $1 הוא ערך בלתי תקין.", 	["ids-invalid"] = "פרמטר מזהים $1 אינו תקין.", 	["polygon-required-points"] = "פוליגון דורש מינימום של 4 נקודות ציון.", 	["polygon-not-closed"] = "פוליגון סגור דורש שהנקודה הראשונה תהיה זהה לנקודה האחרונה.", 	['ids-not-found'] = "מזהים לא נמצאו עבור מידע חיצוני.", 	['not-from-content-page'] = "Do not invoke from content page. Use a template or use a module subpage like /sandbox for testing .", 	-- local categories 	['cat-several-features'] = "", 	['cat-linestring-drawn'] = "", 	['cat-polygon-drawn'] = "", }  local cat = {['cat-several-features'] = false, ['cat-linestring-drawn'] = false, ['cat-polygon-drawn'] = false}  -- Credit to http://stackoverflow.com/a/1283608/2644759, cc-by-sa 3.0 local function tableMerge(t1, t2) 	for k, v in pairs(t2) do 		if type(v) == "table" then 			if type(t1[k] or false) == "table" then 				tableMerge(t1[k] or {}, t2[k] or {}) 			else 				t1[k] = v 			end 		else 			t1[k] = v 		end 	end 	return t1 end  local function loadI18n() 	local exist, res = pcall(require, "Module:מפה/i18n") 	if exist and next(res) ~= nil then 		tableMerge(i18n, res.i18n) 	end end loadI18n()  local errormessage local function printError(key, par) 	-- just print first error 	errormessage = errormessage or ('<span class="error">' .. (par and mw.ustring.gsub(i18n[key], "$1", par) or i18n[key]) .. '</span>') end  -- Convert coordinates input format to geojson table local function parseGeoSequence(data, geotype) 	local coordsGeo = {} 	for line_coord in mw.text.gsplit(data, ':', true) do -- Polygon - linearRing:linearRing... 		local coordsLine = {} 		for point_coord in mw.text.gsplit(line_coord, ';', true) do -- LineString or MultiPoint - point;point... 			local valid = false 			local val = mw.text.split(point_coord, ',', true) -- Point - lat,lon 			-- allow for elevation 			if #val >= 2 and #val <= 3 then 				local lat = tonumber(val[1]) 				local lon = tonumber(val[2]) 				if lat ~= nil and lon ~= nil then 					table.insert(coordsLine, {lon, lat}) 					valid = true 				end 			end 			if not valid and point_coord ~= '' then printError('coordinate-invalid', point_coord) end 		end 		if geotype == 'Polygon' then 			if #coordsLine < 4 then 				printError('polygon-required-points') 			elseif table.concat(coordsLine[1]) ~= table.concat(coordsLine[#coordsLine]) then 				printError('polygon-not-closed') 			end 		end 		table.insert(coordsGeo, coordsLine) 	end 	 	if geotype == 'Point' then 		coordsGeo = coordsGeo[1][1] 	elseif geotype == "LineString" or geotype == "MultiPoint" then 		coordsGeo = coordsGeo[1] 	elseif geotype ~= 'Polygon' then 		printError('geotype-invalid', geotype) 	end 	     return coordsGeo end  -- data Point - {lon,lat} -- data LineString - { {lon,lat}, {lon,lat}, ... } -- data Polygon - { { {lon,lat}, {lon,lat} }, { {lon,lat}, {lon,lat} }, ... } -- output as LineString format local function mergePoints(stack, merger) 	if merger == nil then return stack end 	for _, val in ipairs(merger) do 		if type(val) == "number" then -- Point format 			stack[#stack + 1] = merger 			break 		elseif type(val[1]) == "table" then -- Polygon format 			for _, val2 in ipairs(val) do 				stack[#stack + 1] = val2 			end 		else -- LineString format 			stack[#stack + 1] = val 		end 	end 	return stack end  local function getCoordBounds(data) 	local latN, latS = -90, 90 	local lonE, lonW = -180, 180 	for i, val in ipairs(data) do 		latN = math.max(val[2], latN) 		latS = math.min(val[2], latS) 		lonE = math.max(val[1], lonE) 		lonW = math.min(val[1], lonW) 	end 	 	return latN, latS, lonE, lonW end  local function getCoordCenter(data) 	local latN, latS, lonE, lonW = getCoordBounds(data) 	 	local latCenter = latS + (latN - latS) / 2 	local lonCenter = lonW + (lonE - lonW) / 2 	 	return lonCenter, latCenter end  -- meters per degree by latitude local function mxdByLat(lat) 	local latRad = math.rad(lat) 	-- see [[Geographic coordinate system#Expressing latitude and longitude as linear units]], by CSGNetwork 	local mxdLat = 111132.92 - 559.82 * math.cos(2 * latRad) + 1.175 * math.cos(4 * latRad) - 0.023 * math.cos(6 * latRad) 	local mxdLon = 111412.84 * math.cos(latRad) - 93.5 * math.cos(3 * latRad) + 0.118 * math.cos(5 * latRad) 	return mxdLat, mxdLon end  -- Calculate zoom to fit coordinate bounds into height and width of frame local function getZoom(data, height, width) 	local lat1, lat2, lon1, lon2 = getCoordBounds(data) 	 	local latMid = (lat1 + lat2) / 2 -- mid latitude 	local mxdLat, mxdLon = mxdByLat(latMid) 	-- distances in meters 	local distLat = math.abs((lat1 - lat2) * mxdLat) 	local distLon = math.abs((lon1 - lon2) * mxdLon) 	 	-- margin 100px in height and width, right upper icon is about 50x50px 	local validHeight = math.max(height - 100, 100) 	local validWidth = math.max(width - 100, 100) 	 	-- maximum zoom fitting all points 	local latRad = math.rad(latMid) 	for zoom = 18, 0, -1 do 		-- see https://wiki.openstreetmap.org/wiki/Zoom_levels#Metres_per_pixel_math 		-- equatorial circumference 40 075 036 m: [[Equator#Exact length]] 		local distLatFrame = 40075036 * validHeight * math.cos(latRad) / (2 ^ (zoom + 8)) 		local distLonFrame = 40075036 * validWidth * math.cos(latRad) / (2 ^ (zoom + 8)) 		if distLatFrame > distLat and distLonFrame > distLon then 			return zoom 		end 	end 	 	return 0 end  -- Geotype based on coordinates format pattern local function findGeotype(coord) 	local _, semicolons = string.gsub(coord, ';', '') 	local firstcoord = string.match(coord, "[0-9%.%-]+%s*,%s*[0-9%.%-]+") 	local lastcoord = string.match(string.reverse(coord), "[0-9%.%-]+%s*,%s*[0-9%.%-]+") 	if firstcoord == nil or lastcoord == nil then 		printError('coordinate-invalid', coord) 	else 		lastcoord = string.reverse(lastcoord) 	end 	if string.find(coord, ':') or (semicolons > 2 and firstcoord == lastcoord) then 		return 'Polygon' 	elseif semicolons > 0 then 		return 'LineString' -- or MultiPoint 	else 		return 'Point' 	end end  local function fetchWikidata(id, snak) 	-- snak is a table like {'claims', 'P625', 1, 'mainsnak', 'datavalue', 'value'} 	-- see function ViewSomething on Module:Wikidata 	local value 	id = mw.text.trim(id) 	if not string.find(id, "^Q%d+$") then 		printError('ids-invalid', id) 	else 		value = {['claims']= {} } 		value.claims[snak[2]] = mw.wikibase.getBestStatements(id, snak[2]) 		for i in ipairs(snak) do 			if value == nil then break end 			value = value[snak[i]] 		end 	end 	 	return value end  -- Fetch coordinates from Wikidata for a list of comma separated ids local function getCoordinatesById(ids) 	if ids == nil then return end 	local coord = {} 	local snak = {'claims', 'P625', 1, 'mainsnak', 'datavalue', 'value'} 	for idx in mw.text.gsplit(ids, '%s*,%s*') do 		local value = fetchWikidata(idx, snak) 		if value then 			coord[#coord+1] = value.latitude .. ',' .. value.longitude 		end 	end 	 	return #coord > 0 and table.concat(coord, ';') or nil end  local function getBoundsById(ids, coordInput) 	if ids == nil then return {} end 	local coord = mw.text.split(coordInput, '%s*;%s*') 	local id = mw.text.split(ids, '%s*,%s*') 	if #coord ~= #id then return {} end 	local bounds = {} 	-- try to fetch Wikidata in this order: area, watershed area, population 	local snak_area = {'claims', 'P2046', 1, 'mainsnak', 'datavalue', 'value'} -- area and unit 	local snak_warea = {'claims', 'P2053', 1, 'mainsnak', 'datavalue', 'value'} -- area and unit 	local snak_pop = {'claims', 'P1082', 1, 'mainsnak', 'datavalue', 'value'} -- population 	local convert_area = {['Q712226'] = 1000000, ['Q35852'] = 10000, ['Q232291'] = 2589988.110336, ['Q81292'] = 4046.8564224, 		['Q935614'] = 1600, ['Q857027'] = 0.09290304, ['Q21074767'] = 1138100, ['Q25343'] = 1} -- to square metres 		-- query Wikidata: http://tinyurl.com/j8aez2g 	for i = 1, #id do 		local amount, unit, area 		local value = fetchWikidata(id[i], snak_area) or fetchWikidata(id[i], snak_warea) 		if value then 			amount = tonumber(value.amount) 			unit = string.match(value.unit, "(Q%d+)") 			if convert_area[unit] then 				area = amount * convert_area[unit] 			end 		end 		if area == nil then 			value = fetchWikidata(id[i], snak_pop) 			if value then 				amount = tonumber(value.amount) 				-- average density estimated for populated areas: 100; see [[Population density]] 				area = amount / 100 * 1000000 			end 		end 		if area then 			local radius = math.sqrt(area / math.pi) -- approximation with a circle 			local latlon = mw.text.split(coord[i], '%s*,%s*') 			local mxdLat, mxdLon = mxdByLat(latlon[1]) 			bounds[#bounds+1] = {latlon[2] + (radius / mxdLon), latlon[1] + (radius / mxdLat)} -- NE bound, geoJSON format 			bounds[#bounds+1] = {latlon[2] - (radius / mxdLon), latlon[1] - (radius / mxdLat)} -- SW bound 		end 	end 	return bounds end  local function addCategories(geotype, i) 	if not mw.title.getCurrentTitle().isContentPage then return end 	 	if i > 2 and i18n["cat-several-features"] ~= '' then 		cat["cat-several-features"] = true 	end 	if geotype == "LineString" and i18n["cat-linestring-drawn"] ~= '' then 		cat["cat-linestring-drawn"] = true 	elseif geotype == "Polygon" and i18n["cat-polygon-drawn"] ~= '' then 		cat["cat-polygon-drawn"] = true 	end 	return end  -- Main function function p._tag(args) 	local tagname = args.type or 'mapframe' 	if tagname ~= 'maplink' and tagname ~= 'mapframe' then printError('type-invalid', tagname) end 	 	local geojson 	local tagArgs = { 		text = args['טקסט'], 		zoom = tonumber(args['זום']), 		latitude = tonumber(args['רוחב']), 		longitude = tonumber(args['אורך']) 	} 	local defaultzoom = tonumber(args['זום ברירת מחדל']) 	if tagname == 'mapframe' then 		tagArgs.width = args['רוחב מפה'] or 300 		tagArgs.height = args['אורך מפה'] or 300 		tagArgs.align = args['יישור'] or 'left' 		if args['ללא מסגרת'] ~= nil and tagArgs.text == nil then tagArgs.frameless = true end 	else 		tagArgs.class = args.class 	end 	 	if args['קואורדינטות1'] == nil and args['geotype1'] == nil then -- single feature 		args['קואורדינטות1'] = args['קואורדינטות'] or args[1] 		if args['קואורדינטות1'] == nil and args['רוחב'] and args['אורך'] then 			args['קואורדינטות1'] = args['רוחב'] .. ',' .. args['אורך'] 		elseif args['קואורדינטות1'] == nil then 			args['קואורדינטות1'] = getCoordinatesById(mw.wikibase.getEntityIdForCurrentPage()) 		end 		args['שם1'] = args['שם1'] or args['שם'] 		args['תמונה1'] = args['תמונה1'] or args['תמונה'] 		args['תיאור1'] = args['תיאור1'] or args['תיאור'] 		args['geotype1'] = args['geotype1'] or args['geotype'] 	end 	 	local externalData = {['geoshape'] = true, ['geomask'] = true, ['geoline'] = true} 	local featureCollection = {['Point'] = true, ['MultiPoint'] = true, ['LineString'] = true, ['Polygon'] = true} 	local myfeatures, myexternal, allpoints = {}, {}, {} 	local i, j = 1, 1 	while args['קואורדינטות'..i] or externalData[args['geotype'..i]] do 		local geotypex = args['geotype'..i] or args['geotype'] 		if geotypex ~= nil and not (featureCollection[geotypex] or externalData[geotypex]) then 			printError('geotype-invalid', geotypex) 			break 		end 		 		local mystack 		if externalData[geotypex or ''] then 			mystack = myexternal 			j = #mystack + 1 			mystack[j] = {} 			mystack[j]['type'] = "ExternalData" 			mystack[j]['service'] = geotypex 			mystack[j]['ids'] = args['פריטים'..i] or args['פריטים'] or mw.wikibase.getEntityIdForCurrentPage() 			if mystack[j]['ids'] == nil then printError('ids-not-found'); break end 			local mycoordinates = args['קואורדינטות'..i] 			if mycoordinates == nil and (tagArgs.latitude == nil or tagArgs.longitude == nil or tagArgs.zoom == nil) then 				mycoordinates = getCoordinatesById(mystack[j]['ids']) 			end 			if mycoordinates ~= nil then 				local mypoints = getBoundsById(mystack[j]['ids'], mycoordinates) 				if #mypoints == 0 then 					mypoints = parseGeoSequence(mycoordinates, mycoordinates:find(';') and 'MultiPoint' or 'Point') 				end 				allpoints = mergePoints(allpoints, mypoints) 			end 		else 			mystack = myfeatures 			j = #mystack + 1 			mystack[j] = {} 			mystack[j]['type'] = "Feature" 			mystack[j]['geometry'] = {} 			mystack[j]['geometry']['type'] = geotypex or findGeotype(args['קואורדינטות'..i]) 			mystack[j]['geometry']['coordinates'] = parseGeoSequence(args['קואורדינטות'..i], mystack[j]['geometry']['type']) 			allpoints = mergePoints(allpoints, mystack[j]['geometry']['coordinates']) 			addCategories(mystack[j]['geometry']['type'], i) 		end 		mystack[j]['properties'] = {} 		mystack[j]['properties']['title'] = args['שם'..i] or (geotypex and geotypex .. i) or mystack[j]['geometry']['type'] .. i 		if args['תמונה'..i] then 			args['תיאור'..i] = (args['תיאור'..i] or '') .. '[[File:' .. args['תמונה'..i] .. '|300px]]' 		end 		mystack[j]['properties']['description'] = args['תיאור'..i] 		mystack[j]['properties']['marker-size'] = args['גודל סמן'..i] or args['גודל סמן'] 		mystack[j]['properties']['marker-symbol'] = args['סמל סמן'..i] or args['סמל סמן'] 		mystack[j]['properties']['marker-color'] = args['צבע סמן'..i] or args['צבע סמן'] 		mystack[j]['properties']['stroke'] = args['צבע קו מתאר'..i] or args['צבע קו מתאר'] 		mystack[j]['properties']['stroke-opacity'] = tonumber(args['אטימות קו מתאר'..i] or args['אטימות קו מתאר']) 		mystack[j]['properties']['stroke-width'] = tonumber(args['עובי קו מתאר'..i] or args['עובי קו מתאר']) 		mystack[j]['properties']['fill'] = args['מילוי'..i] or args['מילוי'] 		mystack[j]['properties']['fill-opacity'] = tonumber(args['אטימות מילוי'..i] or args['אטימות מילוי']) 		 		i = i + 1 	end 	 	-- calculate defaults for static mapframe; maplink is dynamic 	if (tagArgs.latitude == nil or tagArgs.longitude == nil) and #allpoints > 0 then 		if tagname == "mapframe" or tagArgs.text == nil then -- coordinates needed for text in maplink 			tagArgs.longitude, tagArgs.latitude = getCoordCenter(allpoints) 		end 	end 	if tagArgs.zoom == nil then 		if tagname == "mapframe" then 			if #allpoints == 1 then 				local currentId = mw.wikibase.getEntityIdForCurrentPage() 				local coordInput = allpoints[1][2] .. ',' .. allpoints[1][1] 				local mybounds = getBoundsById(currentId, coordInput) -- try to fetch by area 				allpoints = mergePoints(allpoints, mybounds) 			end 			if #allpoints <= 1 then 				tagArgs.zoom = defaultzoom or 9 			else 				tagArgs.zoom = getZoom(allpoints, tagArgs.height, tagArgs.width) 			end 		else 			tagArgs.zoom = defaultzoom 		end 	end 	 	local geojson = myexternal 	if #myfeatures > 0 then 		geojson[#geojson + 1] = {type = "FeatureCollection", features = myfeatures} 	end 	 	if args.debug ~= nil then 		local html = mw.text.tag{name = tagname, attrs = tagArgs, content = mw.text.jsonEncode(geojson, mw.text.JSON_PRETTY)} 		return 'syntaxhighlight', tostring(html) .. ' Arguments:' .. mw.text.jsonEncode(args, mw.text.JSON_PRETTY), {lang = 'json'} 	end 	 	return tagname, geojson and mw.text.jsonEncode(geojson) or '', tagArgs end  function p.tag(frame) 	if mw.title.new(frame:getParent():getTitle()).isContentPage and not mw.title.new(frame:getTitle()).isSubpage then 		-- invoked from a content page and not invoking a module subpage 		printError('not-from-content-page') 	end 	local getArgs = require('Module:Arguments').getArgs 	local args = getArgs(frame) 	local tag, geojson, tagArgs = p._tag(args) 	 	local categories = '' 	 	if errormessage then 		categories = mw.message.new('Kartographer-broken-category'):inLanguage(mw.language.getContentLanguage().code):plain() 		return errormessage .. '[[Category:' .. categories .. ']]' 	end 	 	 	return frame:extensionTag(tag, geojson, tagArgs) .. categories end  return p