require('strict')local getArgs = require('Module:Arguments').getArgslocal p =
local log2 = 0.693147181local ppm = 1000/0.3 -- pixels per meter, from 0.3 mm / pixel from https://wiki.openstreetmap.org/wiki/Zoom_levels
-- To convert to OSM zoom level, we need to know meters per pixel at zoom level 9-- On the equator, it's 305.748 meters/pixel according to https://wiki.openstreetmap.org/wiki/Zoom_levels-- This quantity depends on the latitude (which we don't have easy access to)-- Instead, we'll be correct at 30N, cos(30 degrees) = sqrt(3)/2local metersPerPixelLevel9 = 305.748*math.sqrt(3)/2
-- Convert from Geohack's scale to OSM style zoom levels as used by
local positiveNumericArgs =
local function cleanArgs(args) local clean = if type(args)
-- compute the viewport size (on screen) in meters, assuming ppm pixels per meter on screenlocal function computeViewport(args) local viewport_cm = tonumber(args.viewport_cm) local viewport_px = tonumber(args.viewport_px) return viewport_cm and viewport_cm / 100 or viewport_px and viewport_px / ppm or tonumber(args.default_viewport) or 0.1end
-- convert from geohack dim (knowing the viewpoint size on screen) to geohack scalelocal function geohackDimToScale(dim, args) dim = tonumber(dim) args = args or if not dim or dim <= 0 then return end local units = args.units if units and string.lower(units)
-- inverse of above function, returning dim in kmlocal function geohackScaleToDim(scale, args) scale = tonumber(scale) args = args or if not scale or scale <= 0 then return end return scale * computeViewport(args) * 1e-3end
local oddShape = 2.09 --- length/sqrt(area) of Boston (to choose an example)
-- Convert from Geohack's types to Geohack dimlocal function geohackTypeToDim(args) local type = args.type local typeDim = mw.loadData('Module:Infobox_dim/sandbox/data') local dim = typeDim[type] local population = tonumber(args.population) if type
-- Convert from dimension of object to Geohack dimlocal function computeDim(length,width,area) if length and width then return math.max(length,width) end if length then return length end if width then return width end if area then return oddShape*math.sqrt(area) endend
-- compute geohack dim from unit arguments (e.g., length_mi)local function convertDim(args) 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 dimend
local function computeScale(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*)") args.units = units args.default_viewport = 0.1 -- default geohack viewpoirt scale = geohackDimToScale(dim, args) end if not scale then dim = convertDim(args) or geohackTypeToDim(args) args.units = 'km' args.default_viewport = 0.2 --- when object dimensions or type is specified, assume 20cm viewport scale = dim and geohackDimToScale(dim, args) end if not scale then return end scale = math.floor(scale+0.5) -- keep scale within sane bounds if scale < 2000 then scale = 2000 end if scale > 250e6 then scale = 250e6 end return scaleend
-- Module entry pointsfunction p._dim(args) args = cleanArgs(args) if args.dim then return args.dim end -- compute scale for geohack local scale = args.scale local dim if not scale then args.default_viewport = 0.2 -- when specifying a object dimension or type, assume output spans 20cm dim = convertDim(args) or geohackTypeToDim(args) args.units = 'km' scale = dim and geohackDimToScale(dim, args) end -- reset back to 10cm viewport for correct geohack dim output args.viewport_cm = 10 dim = scale and geohackScaleToDim(scale, args) return dim and tostring(math.floor(dim+0.5))..'km'end
function p._scale(args) args = cleanArgs(args) return computeScale(args)end
function p._zoom(args) args = cleanArgs(args) args.viewport_px = args.viewport_px or 200 --- viewport for Kartographer is 200px high local scale = computeScale(args) if scale then local zoom = geohackScaleToMapZoom(scale) return zoom and math.floor(zoom) endend
-- Template entry pointsfunction 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