Modul:GeoData: Unterschied zwischen den Versionen
Erscheinungsbild
Inhalt gelöscht Inhalt hinzugefügt
K unterschiedliche Abweichungen |
K +maxZoomLevel (= 19) |
||
Zeile 49: | Zeile 49: | ||
-- zoom level 19 -> 1:1000, 0 -> 500000000 |
-- zoom level 19 -> 1:1000, 0 -> 500000000 |
||
local maxZoomLevel = 19 |
|||
local scales = { 1000, 2000, 4000, 8000, 15000, 35000, 70000, 150000, 250000, |
local scales = { 1000, 2000, 4000, 8000, 15000, 35000, 70000, 150000, 250000, |
||
500000, 1000000, 2000000, 4000000, 10000000, 15000000, 35000000, 70000000, |
500000, 1000000, 2000000, 4000000, 10000000, 15000000, 35000000, 70000000, |
||
Zeile 93: | Zeile 94: | ||
-- Helper function getZoomFromScale |
-- Helper function getZoomFromScale |
||
function gd.getZoomFromScale( scale ) |
function gd.getZoomFromScale( scale ) |
||
if scale <= scales[1] then return |
if scale <= scales[1] then return maxZoomLevel end |
||
for i = 2, #scales, 1 do |
for i = 2, #scales, 1 do |
||
if (scale > scales[i-1]) and (scale <= scales[i]) |
if (scale > scales[i-1]) and (scale <= scales[i]) |
||
then return |
then return maxZoomLevel+1-i end |
||
end |
end |
||
return 0 |
return 0 |
||
Zeile 376: | Zeile 377: | ||
if args.zoom ~= '' then |
if args.zoom ~= '' then |
||
args.zoom = round( args.zoom ) |
args.zoom = round( args.zoom ) |
||
if (args.zoom < 0) and (args.zoom > |
if (args.zoom < 0) and (args.zoom > maxZoomLevel) then args.zoom = '' end |
||
end |
end |
||
if (args.scale == '') and (args.zoom ~= '') then |
if (args.scale == '') and (args.zoom ~= '') then |
||
args.scale = scales[ |
args.scale = scales[maxZoomLevel+1-args.zoom] |
||
end |
end |
||
if (args.dim == '') and (args.scale ~= '') then |
if (args.dim == '') and (args.scale ~= '') then |
Version vom 8. November 2018, 10:57 Uhr
Dokumentation für das Modul GeoData[Ansicht] [Bearbeiten] [Versionsgeschichte] [ ]
Dieses Modul ist getestet und für den projektweiten Gebrauch geeignet. Es kann in Vorlagen benutzt und auf Hilfeseiten erläutert werden. Entwicklungen an dem Modul sollten auf GeoData/Test und die Anwendung auf der Spielwiese getestet werden, da wiederholte Trial-and-Error-Edits die Resourcen stark belasten können. |
Dieses Modul benutzt die Wikidata-Eigenschaften:
|
Dieses Modul enthält Funktionen zur Anzeige von geografischen Koordinaten für die Vorlagen {{Coord}} und {{GeoData}}.
Die Modulbeschreibung befindet sich in Wikivoyage:GeoData.
Versionsbezeichnung auf Wikidata: keine Version verfügbar
Benötigte weitere Module
Hinweise
- Die obige Dokumentation wurde aus der Seite Modul:GeoData/Doku eingefügt. (bearbeiten | Versionsgeschichte) Die Kategorien für dieses Modul sollten in der Dokumentation eingetragen werden. Die Interwiki-Links sollten auf Wikidata eingepflegt werden.
- Liste der Unterseiten
-- Functions for the presentation of locations coordinate pairs
-- module import
local cd = require( 'Module:Coordinates' )
local pm = require( 'Module:GeoData/Params' )
local gi = require( 'Module:GeoData/i18n' )
local fw = require( 'Module:FastWikidata' )
local gc = require( 'Module:Great circle distance' )
-- module variable
local gd = {}
local possibleFormats = {'f1', 'f2', 'f3', 'f4', 'dec'}
local lengthUnits = {
['http://www.wikidata.org/entity/Q11573'] = { 'm', 1 },
['http://www.wikidata.org/entity/Q828224'] = { 'km', 1000 },
['http://www.wikidata.org/entity/Q174789'] = { 'mm', 0.001 },
['http://www.wikidata.org/entity/Q218593'] = { 'in', 39.370 },
['http://www.wikidata.org/entity/Q253276'] = { 'mi', 0.000621 },
['http://www.wikidata.org/entity/Q3710'] = { 'ft', 3.2808 },
['http://www.wikidata.org/entity/Q174728'] = { 'cm', 0.01 },
['http://www.wikidata.org/entity/Q848856'] = {'dam', 10 },
['http://www.wikidata.org/entity/Q200323'] = { 'dm', 0.1 }
}
local scalesByType = {
adm1st = 1000000,
adm2nd = 300000,
adm3rd = 100000,
airport = 30000,
city = 100000,
country = 10000000,
edu = 10000,
event = 50000,
forest = 50000,
glacier = 50000,
isle = 100000,
landmark = 10000,
mountain = 100000,
pass = 10000,
railwaystation = 10000,
river = 100000,
satellite = 10000000,
waterbody = 100000,
camera = 10000,
default = 300000
}
-- zoom level 19 -> 1:1000, 0 -> 500000000
local maxZoomLevel = 19
local scales = { 1000, 2000, 4000, 8000, 15000, 35000, 70000, 150000, 250000,
500000, 1000000, 2000000, 4000000, 10000000, 15000000, 35000000, 70000000,
150000000, 250000000, 500000000 }
-- getIso3166_1 returns ISO 3166-1 country code from WD
function gd.getIso3166_1( id )
-- in case of the country itself P17 is set, too
local country = fw.getId( id, 'P17' )
if country ~= '' then return fw.getValue( country, 'P297' ) end
return ''
end
-- getLengthFromWD returns a length by property from WD
function gd.getLengthFromWD( id, p )
local w = fw.getValue( id, p )
local r = 0, a, u, t
if w ~= '' then
a = tonumber( w.amount or '' ) or 0
if a ~= 0 then
u = w.unit or ''
if u ~= '' then
t = lengthUnits[u]
if t then r = a * t[2] end
end
end
end
return r
end
-- Helper function roundScale
function gd.roundScale( scale )
if scale <= scales[1] then return scales[1] end
for i = 2, #scales, 1 do
if (scale > scales[i-1]) and (scale <= scales[i])
then return scales[i] end
end
return scales[#scales]
end
-- Helper function getZoomFromScale
function gd.getZoomFromScale( scale )
if scale <= scales[1] then return maxZoomLevel end
for i = 2, #scales, 1 do
if (scale > scales[i-1]) and (scale <= scales[i])
then return maxZoomLevel+1-i end
end
return 0
end
-- Local helper functions
-- helper function round
-- n: value to round
-- idp: number of digits after the decimal point
local function round( n, idp )
local m = 10^( idp or 0 )
if n >= 0 then return math.floor( n * m + 0.5 ) / m
else return math.ceil( n * m - 0.5 ) / m
end
end
local function checkFormat( f )
if type( f ) == 'table' then return f end
local r = false
for i = 1, #possibleFormats, 1 do
if possibleFormats[i] == f then r = true end
end
if r then return f else return 'f1' end
end
local function checkNumber( s )
if s == '' then return s end
local n = tonumber( s )
if n == nil then return '' else return n end
end
-- helper function getPrecision
-- returns integer precision number
-- possible values: numbers, D, DM, DMS
local function getPrecision( prec )
local p = tonumber( prec )
if p ~= nil then
p = round( p, 0 )
if p < -1 then p = -1 end
if p > 8 then p = 8 end -- maximum 8 decimals
if p == 1 then p = 2 end
if p == 3 then p = 4 end
return p
else
p = prec and prec:upper() or 'DMS'
if p == 'D' then return 0
elseif p == 'DM' then return 2
elseif p == 'DMS' then return 4
else return ''
end
end
end
-- getPrecisionFromSize gives precision number for toDMS function calculated
-- from the maximum of the dimension of a geographic object or the measurement
-- error of the coordinate (as a radius)
-- 1° correlates to about 1852 meters
-- 1852 meters give precision = 2 (1')
local function getPrecisionFromSize( dim, err )
local d = tonumber( dim ) or 4000
if err ~= '' then
local m = tonumber( err ) or 0
if m > d/2 then d = 2 * m end
end
if d < 1 then d = 1 end
-- 2 * 60 * 1852 = 222240
d = math.ceil ( math.log10 ( 222240 / d ) )
if d < 0 then d = 0 end
if d > 5 then d = 5 end
if d == 1 then d = 2 end
if d == 3 then d = 4 end
return d
end
-- getExtraParameters returns a string with extra Geohack parameters as it is
-- used by Special:Mapsources and {{#coordinates}}
local function getExtraParameters( args )
local s = 'scale:' .. args.scale
if args.type ~= '' then s = s .. '_type:' .. args.type end
if args.dim ~= '' then s = s .. '_dim:' .. args.dim end
s = s .. '_globe:' .. args.globe
if args.region ~= '' then s = s .. '_region:' .. args.region end
return s
end
-- Helper function for microformat creation
local function getMicroformat( aName, addClasses )
local s = '<span class="h-card'
if (addClasses ~= nil) and (addClasses ~= '') then
s = s .. ' ' .. addClasses
end
s = s .. '"><span class="p-geo geo" style="display: none;">'
.. '<span class="p-latitude latitude">$5</span>, '
.. '<span class="p-longitude longitude">$6</span>'
.. '</span>'
.. '<span class="p-name" style="display: none;">' ..aName .. '</span>'
.. '</span>'
return s
end
-- Coordinates shown as article indicator
-- Helper function indicatorTable returns a table containing coordinate text inset
local function indicatorTable( inset, aName, zoom, lat, long )
local c = mw.ustring.gsub( gi.titles.coordinates, '($1)', aName)
local m = mw.ustring.gsub( gi.titles.mapsources, '($1)', aName)
return '<table class="wv-coord-indicator" cellspacing="0" data-zoom="' .. zoom
.. '" data-lat="' .. lat .. '" data-lon="' .. long .. '"><tr>'
.. '<td class="wv-icon" title="' .. c .. '">'
.. '<span class="map-globe-default">' .. gi.titles.globeDefault .. '</span>'
.. '<span class="map-globe-js" style="display: none;">' .. gi.titles.globeJS .. '</span>'
.. '</td><td class="wv-coords printNoLink plainlinks" title="' .. m .. '">'
.. inset .. '</td>'
.. '</tr></table>'
end
-- Helper function to get data from Wikidata by id
-- gets name, dimension, latitude, and longitude
-- returns an error if no coordinates are available
local function getParamsFromWD( args )
local coordState = {
err = false,
distanceErr = 0,
fromWD = false
}
local d = 0, c
c = math.abs( tonumber( args.dim ) or 0 )
if c >= 1 then d = c end
if ((args.lat == '') or (args.lat == 0)) and
((args.long == '') or (args.long == 0)) then coordState.err = true end
if args.id ~= '' then
if args.name == '' then
args.name = mw.wikibase.label( args.id ) or ''
end
c = fw.getValue( args.id, 'P625' ) -- coordinates from Wikidata
if ((args.lat == '') or (args.lat == 0)) and
((args.long == '') or (args.long == 0)) then
if c == '' then coordState.err = true
else
args.lat = tonumber( c.latitude )
args.long = tonumber( c.longitude )
coordState.err = false
coordState.fromWD = true
if args.prec == '' then
c.precision = (tonumber( c.precision ) or 0) * 1842
-- 1° ~ 1842 m
if c.precision >= 1 then args.prec = round( c.precision ) end
end
end
else
if c ~= '' then
-- GeoData and Wikidata positions may differ
coordState.distanceErr = gc.getGcd( cd.toDec( args.lat, 'lat', 8 ).dec,
cd.toDec( args.long, 'long', 8 ).dec,
tonumber( c.latitude ), tonumber( c.longitude ) )
end
end
if d < 1 then
d = gd.getLengthFromWD( args.id, 'P2043' ) -- length
local width = gd.getLengthFromWD( args.id, 'P2049' )
if width > d then d = width end
end
end
if d < 1 then args.dim = '' else args.dim = round( d ) end
return args, coordState
end
-- Display the coordinates
function gd.displayCoords( args, frame )
args.lat = args[1] or args.lat or args.NS or '' -- NS/EW: fallback
args.long = args[2] or args.long or args.EW or ''
args.name = args.name or ''
args.display = args.display and args.display:lower() or 'inline'
args.format = checkFormat( args.format and args.format:lower() or 'f1' )
args.addMf = args.addMf and args.addMf:lower() or ''
-- if 'true' then add microformat and {{#coordinates}}
args.id = fw.checkId( args.id )
args.region = args.region and args.region:upper() or ''
args.dim = checkNumber( args.dim or '' )
args.globe = args.globe and args.globe:lower() or 'earth'
args.precision = getPrecision( args.precision or '' ) -- display precission
args.prec = checkNumber( args.prec or '' ) -- measurement error
args.radius = checkNumber( args.radius or '' )
args.scale = checkNumber( args.scale or '' )
args.zoom = checkNumber( args.zoom or '' )
args.type = args.type and args.type:lower() or ''
if not scalesByType[args.type] then args.type = '' end
local cat = '' -- tracking categories
-- Parameter check
local function isBox( s )
return s:find('box') ~= nil
end
local function fIsInline( s ) -- inline in any case
return s:find('inline') ~= nil or s:find('box') ~= nil
or s == 'i' or s == 'it' or s == 'ti'
end
local isInline = fIsInline( args.display )
local function fIsInTitle( s ) -- intitle in any case
return s:find('title') ~= nil or s == 't' or s == 'it' or s == 'ti'
end
local isInTitle = fIsInTitle( args.display )
local articleId = mw.wikibase.getEntityIdForCurrentPage() or ''
if isInTitle then
if args.id == '' then args.id = articleId end
end
if args.region == '' then
if args.id == '' then
if articleId ~= '' then args.region = gd.getIso3166_1( articleId ) end
else
args.region = gd.getIso3166_1( args.id )
end
end
-- in future add the region (P300 like EG-LX), too
if (args.dim == '') and (args.radius ~= '') then
args.dim = round( 2 * args.radius )
end
if (args.scale == '') and (args.type ~= '') then
args.scale = scalesByType[args.type]
end
local coordState
args, coordState = getParamsFromWD( args )
if coordState.err then
if isInTitle then
return gi.categories.geoWithoutCoords
else
return gi.categories.coordWithoutCoords
end
end
if coordState.distanceErr > 50 then
cat = cat .. gi.categories.differentPositions50
elseif coordState.distanceErr > 25 then
cat = cat .. gi.categories.differentPositions25
elseif coordState.distanceErr > 10 then
cat = cat .. gi.categories.differentPositions
end
if coordState.fromWD then
cat = cat .. gi.categories.fromWikidata
end
local withoutScale = true
if ( args.dim ~= '' ) or ( args.radius ~= '' ) or ( args.zoom ~= '' ) or
( args.scale ~= '' ) then
withoutScale = false
end
if withoutScale then
cat = cat .. gi.categories.withoutScale
end
if args.name == '' then
args.name = gi.errorMsg.missingName
cat = cat .. gi.categories.coordWithoutName
end
-- for compatibility with WV/en: args.zoom
if args.zoom ~= '' then
args.zoom = round( args.zoom )
if (args.zoom < 0) and (args.zoom > maxZoomLevel) then args.zoom = '' end
end
if (args.scale == '') and (args.zoom ~= '') then
args.scale = scales[maxZoomLevel+1-args.zoom]
end
if (args.dim == '') and (args.scale ~= '') then
args.dim = args.scale / 5
end
if (args.dim == '') and (args.scale == '') then args.dim = 4000 end
if (args.scale == '') then args.scale = 5 * args.dim end
args.scale = gd.roundScale( args.scale )
if args.precision == '' then -- mainly for geo/geoData
args.precision = getPrecisionFromSize( args.dim, args.prec )
end
local extra = getExtraParameters( args )
local pattern
local parserFc
local mf
local aLat
local aLong
-- inline coordinates
local v = ''
if isInline then
pattern = '<span class="printNoLink plainlinks'
if isBox( args.display ) then
pattern = pattern .. ' coordBox">'
else pattern = pattern .. '">' end
mf = ''
if (args.addMf == 'true') and not isInTitle then -- adding microformat
mf = getMicroformat( args.name, 'listing-coordinates' )
end
pattern = mf .. pattern
.. '[' .. gi.coordURL .. '$1_$2_' .. mw.uri.encode( extra, 'QUERY' )
.. '&locname=' .. mw.uri.encode( args.name, 'QUERY' )
.. ' <span class="coordStyle" title="' .. gi.titles.latitude .. '">$3</span>'
.. ' <span class="coordStyle" title="' .. gi.titles.longitude .. '">$4</span>]'
.. '</span>'
if args.format == 'dec' then
v, aLat, aLong =
cd.getDecGeoLink( pattern, args.lat, args.long, args.precision )
else
v, aLat, aLong =
cd.getGeoLink( pattern, args.lat, args.long, '', '', '', '',
args.precision, args.format )
end
-- adding {{#coordinates}}
parserFc = ''
if (frame ~= nil) and (args.addMf == 'true') and not isInTitle then
parserFc = frame:callParserFunction{ name = '#coordinates',
args = { aLat, aLong, extra, name = args.name } }
end
v = v .. parserFc .. cat
end
-- indicator/in title coordinates
local w = ''
if isInTitle then
mf = ''
if args.addMf == 'true' then -- adding microformat
mf = getMicroformat( args.name, '' )
end
pattern = mf
.. '[' .. gi.coordURL .. '$1_$2_' .. mw.uri.encode( extra, 'QUERY' )
.. '&locname=' .. mw.uri.encode( args.name, 'QUERY' ) .. ' $3<br />$4]'
if args.format == 'dec' then
w, aLat, aLong =
cd.getDecGeoLink( pattern, args.lat, args.long, args.precision )
else
w, aLat, aLong =
cd.getGeoLink( pattern, args.lat, args.long, '', '', '', '',
args.precision, args.format )
end
parserFc = ''
if (frame ~= nil) and (args.addMf == 'true') then -- adding {{#coordinates}}
parserFc = frame:callParserFunction{ name = '#coordinates',
args = { 'primary', aLat, aLong, extra, name = args.name } }
end
w = indicatorTable( w, args.name, gd.getZoomFromScale( args.scale ), args.lat, args.long )
.. parserFc .. cat
end
return v .. w
end
-- [[template:Coord]] template
-- format: f1 ... f4, dec
function gd.coord( frame )
local args = frame:getParent().args
args.display = args.display or 'inline'
args.precision = args.precision or '4'
args.addMf = args.addMf or 'true' -- with {{#coordinates}} and microformat
return gd.displayCoords( args, frame ) .. pm._checkParams( args, pm._coord )
end
-- [[template:Geo]] template
-- if id is set then data are alternatively used from Wikidata
-- includes primary {{#coordinate}}
-- calculates precission from the size of the geographical object
function gd.geo( frame )
local args = frame:getParent().args
local title = mw.title.getCurrentTitle()
args.display = args.display or 'title'
args.format = args.format or 'f2'
args.addMf = 'true'
args.name = args.name or title.subpageText
if frame.args.minerva then args.addMf = 'false' end
categs = ''
args.elev = args.elev or ''
args.elevMin = args.elevMin or ''
args.elevMax = args.elevMax or ''
if args.elev .. args.elevMin .. args.elevMax ~= '' then
categs = gi.categories.elevationUsed
end
if title.namespace == 0 then
categs = categs .. gi.categories.hasGeo
end
return gd.displayCoords( args, frame ) .. pm._checkParams( args, pm._geo )
.. categs
end
return gd