Module:Infobox dim
Appearance
![]() | This module is rated as ready for general use. It has reached a mature form and is thought to be relatively bug-free and ready for use wherever appropriate. It is ready to mention on help pages and other Wikipedia resources as an option for new users to learn. To reduce server load and bad output, it should be improved by sandbox testing rather than repeated trial-and-error editing. |
![]() | This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
![]() | This Lua module is used on approximately 250,000 pages. To avoid major disruption and server load, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Consider discussing changes on the talk page before implementing them. |
Code to convert information about physical size of objects into parameters for geohack or mapframes.
The following parameters describe the physical object size:
- length_km
- length_mi
- width_km
- width_mi
- area_km2
- area_mi2
- area_ha
- area_acre
When producing scale or zoom, module can use size of object on screen specified via |viewport_cm=
or |viewport_px=
. Defaults to 10cm, to match geohack.
In addition, the module can accept and convert between geohack parameters:
- dim
- scale
- type (e.g., "mountain" or "city")
- population (for type="city" only)
Usage
{{#invoke:Infobox dim|dim}}
Generates dim string (e.g, "24km") suitable for geohack link
{{#invoke:Infobox dim|scale}}
Generates scale (e.g, 100000) suitable for geohack link
{{#invoke:Infobox dim|zoom}}
Generates Open Street Map zoom level (e.g, 12) suitable for use in mapframes
require('strict')
local getArgs = require('Module:Arguments').getArgs
local p = {}
local log2 = 0.693147181
local ppm = 1000/0.3 -- pixels per meter, from 0.3 mm / pixel
-- Convert from Geohack's scale and dim levels to OSM style zoom levels as used by <maplink>
local function geohackScaleToMapZoom(scale)
scale = tonumber(scale)
if not scale or scale <= 0 then return end
-- Approximation of https://wiki.openstreetmap.org/wiki/Zoom_levels
-- pixel/m from OSM is exact, so use zoom level 9 and 0.3 mm/pixel
return math.log(305.748*ppm/scale)/log2 + 9
end
local function geohackDimToScale(dim, units)
dim = tonumber(dim)
if not dim or dim <= 0 then return end
if units and string.lower(units) == 'km' then
dim = dim*1000
end
-- geohack assumes a map width of 10cm on the screen
-- which seems nuts, but we have to be compatible
-- thus, dim has to correspond to 10cm, so scale is dim (in meters) * 10
return 10 * dim
end
-- inverse of above function, returning dim in km
local function geohackScaleToDim(scale)
scale = tonumber(scale)
if not scale or scale <= 0 then return end
return scale * 1e-4
end
-- Convert from Geohack's types to Geohack's scale levels
local function geohackTypeToScale(type, population)
local typeScale = {
country = 10000000,
satellite = 10000000,
state = 3000000,
adm1st = 1000000,
adm2nd = 300000,
adm3rd = 100000,
city = 100000,
isle = 100000,
mountain = 100000,
river = 100000,
waterbody = 100000,
edu = 10000,
event = 50000,
forest = 50000,
glacier = 50000,
airport = 30000,
landmark = 10000,
railwaystation = 10000,
edu = 10000,
pass = 10000,
camera = 10000
}
local scale
if typeScale[type] then
scale = typeScale[type]
end
population = tonumber(population)
if type == 'city' and population and population > 0 then
-- assume city is a circle with density of 1000/square kilometer
-- compute diameter, in meters
local diam = 35.68*math.sqrt(population)
-- convert to scale
scale = geohackDimToScale(diam)
-- don't zoom in too far
if scale < 25000 then
scale = 25000
end
end
return scale
end
-- Convert from dimension of object to Geohack dim level
local function computeDim(length,width,area)
if length and width then
return 0.5*math.max(length,width)
end
if length then return 0.5*length end
if width then return 0.5*width end
if area then return 0.977*math.sqrt(area) end
end
local function convertDim(args)
for _, arg in pairs({'length_mi','length_km','width_mi','width_km',
'area_mi2','area_km2','area_acre','area_ha'}) do
args[arg] = args[arg] and mw.ustring.gsub(args[arg],",","")
args[arg] = tonumber(args[arg])
if args[arg] and args[arg] <= 0 then args[arg] = nil end
end
local length = args.length_mi and 1.60934*args.length_mi or args.length_km
local width = args.width_mi and 1.60934*args.width_mi or args.width_km
local area = args.area_acre and 0.00404686*args.area_acre or
args.area_ha and 0.01*args.area_ha or
args.area_mi2 and 2.58999*args.area_mi2 or args.area_km2
local dim = computeDim(length, width, area)
return dim
end
-- Module entry points
function p._dim(args)
if args.dim then return args.dim end
local dim = convertDim(args)
if not dim then
local scale = args.scale or geohackTypeToScale(args.type, args.population)
dim = geohackScaleToDim(scale)
end
return dim and tostring(math.floor(dim+0.5))..'km'
end
function p._scale(args)
if args.scale then return args.scale end
local dim, units, scale
if args.dim then
dim, units = mw.ustring.match(args.dim,"^([-%d%.]+)%s*(%D*)")
scale = geohackDimToScale(dim, units)
end
if not scale then
dim = convertDim(args)
scale = dim and geohackDimToScale(dim, 'km')
end
if args.type and not scale then
scale = geohackTypeToScale(args.type, args.population)
end
return scale and math.floor(scale+0.5)
end
function p._zoom(args)
local scale = p._scale(args)
if scale then
local zoom = geohackScaleToMapZoom(scale)
return zoom and math.floor(zoom+0.5)
end
end
-- Template entry points
function p.dim(frame)
return p._dim(getArgs(frame)) or ''
end
function p.scale(frame)
return p._scale(getArgs(frame)) or ''
end
function p.zoom(frame)
return p._zoom(getArgs(frame)) or ''
end
return p