Zum Inhalt springen

Modul:GeoData: Unterschied zwischen den Versionen

Aus Wikivoyage
Inhalt gelöscht Inhalt hinzugefügt
KKeine Bearbeitungszusammenfassung
require( 'strict' )
 
(18 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
-- Functions for the presentation of locations coordinate pairs
-- Functions for the presentation of locations coordinate pairs


-- module variable and administration
-- documentation
local GeoData = {
local gd = {
moduleInterface = {
suite = 'GeoData',
serial = '2020-10-02',
suite = 'GeoData',
serial = '2022-10-22',
item = 94472936
item = 94472936
}
}
}


-- module import
-- module import
-- require( 'strict' )
local cd = require( 'Module:Coordinates' )
local cd = require( 'Module:Coordinates' )
local cm = require( 'Module:CountryData' )
local cm = require( 'Module:CountryData' )
local fw = require( 'Module:Wikidata utilities' )
local gc = require( 'Module:Great circle distance' )
local gc = require( 'Module:Great circle distance' )
local gi = require( 'Module:GeoData/i18n' )
local gi = require( 'Module:GeoData/i18n' )
local gp = require( 'Module:GeoData/Params' )
local gp = require( 'Module:GeoData/Params' )
local lp = require( 'Module:LinkPhone' )

local wu = require( 'Module:Wikidata utilities' )
-- module variable
local gd = {}


local possibleFormats = { 'f1', 'f2', 'f3', 'f4', 'dec' }
local possibleFormats = { 'f1', 'f2', 'f3', 'f4', 'dec' }


local lengthUnits = {
local lengthUnits = {
[ 'Q11573' ] = { 'm', 1 },
["1"] = { 'm', 1 },
[ 'Q828224' ] = { 'km', 1000 },
Q11573 = { 'm', 1 },
[ 'Q174789' ] = { 'mm', 0.001 },
Q828224 = { 'km', 1000 },
[ 'Q218593' ] = { 'in', 39.370 },
Q174789 = { 'mm', 0.001 },
[ 'Q253276' ] = { 'mi', 0.000621 },
Q218593 = { 'in', 0.0254 },
[ 'Q3710' ] = { 'ft', 3.2808 },
Q253276 = { 'mi', 1610 },
[ 'Q174728' ] = { 'cm', 0.01 },
Q3710 = { 'ft', 0.3048 },
[ 'Q848856' ] = { 'dam', 10 },
Q174728 = { 'cm', 0.01 },
[ 'Q200323' ] = { 'dm', 0.1 }
Q848856 = { 'dam', 10 },
Q200323 = { 'dm', 0.1 }
}
}


Zeile 116: Zeile 118:
end
end


for _, fmt in ipairs( possibleFormats ) do
for i, fmt in ipairs( possibleFormats ) do
if fmt == f then
if fmt == f then
return f
return f
Zeile 138: Zeile 140:
p = -1
p = -1
elseif p == 1 then
elseif p == 1 then
P = 2
p = 2
elseif p == 3 then
elseif p == 3 then
P = 4
p = 4
elseif p > 6 then
elseif p > 6 then
p = 6 -- maximum 6 decimals
p = 6 -- maximum 6 decimals
Zeile 162: Zeile 164:
-- from the maximum of the dimension of a geographic object or the measurement
-- from the maximum of the dimension of a geographic object or the measurement
-- error of the coordinate (as a radius)
-- error of the coordinate (as a radius)
-- 1° correlates to about 1852 meters
-- 1° equals about 1852 meters
-- 1852 meters give precision = 2 (1')
-- 1852 meters give precision = 2 (1')
local function getPrecisionFromSize( dim, err )
local function getPrecisionFromSize( dim, err )
Zeile 213: Zeile 215:
return '<span class="h-card'
return '<span class="h-card'
.. ( isSet( addClasses ) and ( ' ' .. addClasses ) or '' )
.. ( isSet( addClasses ) and ( ' ' .. addClasses ) or '' )
.. '"><span class="p-geo geo" style="display: none;">'
.. '" style="display: none;">'
.. '<span class="p-latitude latitude">$5</span>, '
.. '<span class="p-geo geo">'
.. '<span class="p-latitude latitude">$5</span>, '
.. '<span class="p-longitude longitude">$6</span>'
.. '<span class="p-longitude longitude">$6</span>'
.. '</span>'
.. '</span>'
.. '<span class="p-name" style="display: none;">' ..aName .. '</span>'
.. '<span class="p-name">' ..aName .. '</span>'
.. '</span>'
.. '</span>'
end
end
Zeile 239: Zeile 242:
end
end


local html = mw.html.create( 'table' )
local html = mw.html.create( 'div' )
:addClass( 'wv-coord-indicator' )
:addClass( 'voy-coord-indicator' )
:attr( 'cellspacing', '0' )
:attr( 'data-zoom', zoom )
:attr( 'data-zoom', zoom )
:attr( 'data-lat', lat )
:attr( 'data-lat', lat )
:attr( 'data-lon', long )
:attr( 'data-lon', long )
:node( mw.html.create( 'tr' )
:node( mw.html.create( 'div' )
:node( mw.html.create( 'td' )
:addClass( 'voy-icon' )
:addClass( 'wv-icon' )
:attr( 'title', c )
:attr( 'title', c )
:node( mw.html.create( 'span' )
:node( mw.html.create( 'span' )
:addClass( 'voy-map-globe-default' )
:addClass( 'map-globe-default' )
:wikitext( gi.titles.globeDefault )
:wikitext( gi.titles.globeDefault )
)
:node( mw.html.create( 'span' )
:addClass( 'map-globe-js' )
:css( 'display', 'none' )
:wikitext( gi.titles.globeJS )
)
)
)
:node( mw.html.create( 'td' )
:node( mw.html.create( 'span' )
:addClass( 'voy-map-globe-js' )
:attr( 'class', 'wv-coords printNoLink plainlinks' )
:attr( 'title', m )
:css( 'display', 'none' )
:wikitext( inset )
:wikitext( gi.titles.globeJS )
)
)
)
:node( mw.html.create( 'div' )
:attr( 'class', 'voy-coords printNoLink plainlinks' )
:attr( 'title', m )
:wikitext( inset )
)
)


-- adding country- and region-related data
-- adding country- and region-related data
if country.id ~= '' then
if country.id ~= '' then
if country.cc ~= '' then
country.trunkPrefix = lp.getTrunkPrefix( country.cc )
end

html:attr( 'data-country', data( country.iso_3166 ) )
html:attr( 'data-country', data( country.iso_3166 ) )
:attr( 'data-country-name', data( country.country ) )
:attr( 'data-country-name', data( country.country ) )
:attr( 'data-adm1st', adm1st )
:attr( 'data-adm1st', adm1st )
:attr( 'data-country-calling-code', data( country.cc ) )
:attr( 'data-country-calling-code', data( country.cc ) )
:attr( 'data-trunk-prefix', data( country.trunkPrefix ) )
:attr( 'data-lang', data( country.lang ) )
:attr( 'data-lang', data( country.lang ) )
:attr( 'data-lang-name', data( country.langName ) )
:attr( 'data-lang-name', data( country.langName ) )
Zeile 283: Zeile 288:
-- getLengthFromWD returns a length by property from WD
-- getLengthFromWD returns a length by property from WD
local function getLengthFromWD( id, p )
local function getLengthFromWD( id, p )
local r = 0
local w = wu.getValue( id, p )
local w = fw.getValue( id, p )
if w == '' then
if w == '' then
return r
return 0
end
end


Zeile 292: Zeile 296:
local u = lengthUnits[ w.unit ]
local u = lengthUnits[ w.unit ]
if u then
if u then
r = a * u[ 2 ]
u = u[ 2 ]
else
u = wu.getValue( w.unit, gi.properties.conversionToSI )
u = u == '' and 0 or tonumber( u.amount ) or 0
end
end


return r
return a * u
end
end


Zeile 337: Zeile 344:


-- getting coordinates in any case
-- getting coordinates in any case
local c = fw.getValue( args.wikidata, gi.properties.centerCoordinates )
local c = wu.getValue( args.wikidata, gi.properties.centerCoordinates )
if c == '' then
if c == '' then
c = fw.getValue( args.wikidata, gi.properties.coordinates )
c = wu.getValue( args.wikidata, gi.properties.coordinates )
end
end
if c ~= '' then
if c ~= '' then
Zeile 367: Zeile 374:


local function makeCoordinates( args, pattern )
local function makeCoordinates( args, pattern )
local r
local s, lat, long
if args.format == 'dec' then
if args.format == 'dec' then
r, _, _ = cd.getDecGeoLink( pattern, args.lat, args.long, args.precision )
s, lat, long = cd.getDecGeoLink( pattern, args.lat, args.long, args.precision )
else
else
r, _, _ = cd.getGeoLink( pattern, args.lat, args.long, '', '', '', '',
s, lat, long = cd.getGeoLink( pattern, args.lat, args.long, '', '', '', '',
args.precision, args.format )
args.precision, args.format )
end
end
return r
return s
end
end


Zeile 404: Zeile 411:


-- Parameter check
-- Parameter check

local function isBox( s )
return s:find( 'box' )
end


local function fIsInline( s ) -- inline in any case
local function fIsInline( s ) -- inline in any case
return s:find( 'inline' ) or s:find( 'box' )
return s:find( 'inline' )
or s == 'i' or s == 'it' or s == 'ti'
or s == 'i' or s == 'it' or s == 'ti'
end
end
Zeile 512: Zeile 515:
if isInline then
if isInline then
v = '<span class="printNoLink plainlinks'
v = '<span class="printNoLink plainlinks'
.. ( isBox( args.display ) and ' coordBox' or '' )
.. '">' .. mf
.. '">' .. mf
.. '[' .. gi.coordURL .. '$1_$2_' .. mw.uri.encode( extra, 'QUERY' )
.. '[' .. gi.coordURL .. '$1_$2_' .. mw.uri.encode( extra, 'QUERY' )
.. '&locname=' .. mw.uri.encode( args.name, 'QUERY' )
.. '&locname=' .. mw.uri.encode( args.name, 'QUERY' )
.. ' <span class="coordStyle" title="' .. gi.titles.latitude .. '">$3</span>'
.. ' <span class="voy-coord-style" title="' .. gi.titles.latitude .. '">$3</span>'
.. ' <span class="coordStyle" title="' .. gi.titles.longitude .. '">$4</span>]'
.. ' <span class="voy-coord-style" title="' .. gi.titles.longitude .. '">$4</span>]'
.. '</span>'
.. '</span>'
v = makeCoordinates( args, v )
v = makeCoordinates( args, v )
Zeile 544: Zeile 546:


v = v .. w .. parserFc .. cat
v = v .. w .. parserFc .. cat
.. ( isNs0 and fw.getCategories( gi.categories.properties ) or '' )
.. ( isNs0 and wu.getCategories( gi.categories.properties ) or '' )
return v
return v
end
end
Zeile 554: Zeile 556:
local ns = mw.title.getCurrentTitle().namespace
local ns = mw.title.getCurrentTitle().namespace


args.display = setValue( args.display, 'inline' )
args.display = 'inline'
args.precision = setValue( args.precision, '4' )
args.precision = setValue( args.precision, '4' )
args.addMf = setValue( args.addMf, 'true' )
args.addMf = 'true'
-- with {{#coordinates}} and microformat
-- with {{#coordinates}} and microformat
return displayCoords( args, frame, ns == 0 ) .. gp._checkParams( args, gp._coord )
return displayCoords( args, frame, ns == 0 ) .. gp.checkParams( args, gp.coord )
end
end


Zeile 572: Zeile 574:
local categs = ''
local categs = ''


args.display = setValue( args.display, 'title' )
args.display = 'title'
args.format = setValue( args.format, 'f2' )
args.format = 'f2'
args.name = setValue( args.name, title.subpageText )
args.name = setValue( args.name, title.subpageText )
args.addMf = frame.args.minerva and 'false' or 'true'
args.addMf = frame.args.minerva and 'false' or 'true'
-- prevent 2nd #coordinates call with Minerva skin
-- prevent 2nd #coordinates call with Minerva skin


-- deprecated parameters
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 isSet( args.prec ) then
categs = categs .. gi.categories.precUsed
end
if ns == 0 then
if ns == 0 then
categs = categs .. gi.categories.hasGeo
categs = categs .. gi.categories.hasGeo
end
end
return displayCoords( args, frame, ns == 0 )
return displayCoords( args, frame, ns == 0 )
.. gp._checkParams( args, gp._geo ) .. categs
.. gp.checkParams( args, gp.geo ) .. categs
end

-- module administration
function gd.GeoData()
return GeoData
end

function gd.failsafe( version )
return fw._failsafe( version, GeoData ) or ''
end
end



Aktuelle Version vom 22. Oktober 2022, 15:40 Uhr

Dokumentation für das Modul GeoData[Ansicht] [Bearbeiten] [Versionsgeschichte] [Aktualisieren]

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: 2022-10-22 Ok!

Benötigte weitere Module

Dieses Modul benötigt folgende weitere Module: Coordinates • CountryData • GeoData/i18n • GeoData/Params • Great circle distance • Wikidata utilities
Hinweise
-- Functions for the presentation of locations coordinate pairs

-- module variable and administration
local gd = {
	moduleInterface = {
		suite  = 'GeoData',
		serial = '2022-10-22',
		item   = 94472936
	}
}

-- module import
-- require( 'strict' )
local cd = require( 'Module:Coordinates' )
local cm = require( 'Module:CountryData' )
local gc = require( 'Module:Great circle distance' )
local gi = require( 'Module:GeoData/i18n' )
local gp = require( 'Module:GeoData/Params' )
local lp = require( 'Module:LinkPhone' )
local wu = require( 'Module:Wikidata utilities' )

local possibleFormats = { 'f1', 'f2', 'f3', 'f4', 'dec' }

local lengthUnits = {
	["1"]   = {   'm', 1      },
	Q11573  = {   'm', 1      },
	Q828224 = {  'km', 1000   },
	Q174789 = {  'mm', 0.001  },
	Q218593 = {  'in', 0.0254 },
	Q253276 = {  'mi', 1610   },
	Q3710   = {  'ft', 0.3048 },
	Q174728 = {  'cm', 0.01   },
	Q848856 = { 'dam', 10     },
	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 }

-- Local helper functions

-- Helper function isSet
local function isSet( param )
	return param and param ~= '';
end

local function setValue( value, default )
	return isSet( value ) and value or default
end

-- Helper function roundScale
local function 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
local function 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 + 2 - i -- because i starts from 2
		end
	end
	return 0
end

-- 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

	for i, fmt in ipairs( possibleFormats ) do
		if fmt == f then
			return f
		end
	end
	return 'f1'
end

local function checkNumber( s )
	return tonumber( s ) or ''
end

-- helper function getPrecision
-- returns integer precision number
-- possible values: numbers, D, DM, DMS
local function getPrecision( prec )
	local p = tonumber( prec )
	if p then
		p = round( p, 0 )
		if p < -1 then
			p = -1
		elseif p == 1 then
			p = 2
		elseif p == 3 then
			p = 4
		elseif p > 6 then
			p = 6 -- maximum 6 decimals
		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° equals 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
	elseif d > 5 then
		d = 5
	end
	if d == 1 then
		d = 2
	elseif 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 )
	return '<span class="h-card'
		.. ( isSet( addClasses ) and ( ' ' .. addClasses ) or '' )
		.. '" style="display: none;">'
			.. '<span class="p-geo geo">'
				.. '<span class="p-latitude latitude">$5</span>, '
				.. '<span class="p-longitude longitude">$6</span>'
			.. '</span>'
			.. '<span class="p-name">' ..aName .. '</span>'
		.. '</span>'
end

-- Coordinates shown as article indicator

-- Helper function indicatorTable returns a table containing coordinate text inset
local function indicatorTable( inset, aName, zoom, lat, long, country )
	local function data( s )
		return isSet( s ) and s or nil
	end

	local c = mw.ustring.gsub( gi.titles.coordinates, '($1)', aName)
	local m = mw.ustring.gsub( gi.titles.mapsources, '($1)', aName)
	local adm1st

	if country.id ~= '' then
		adm1st = country.adm1st or cm.getAdm1st( country.id )
		inset = inset:gsub( '_region%%3A%a+&',
			'_region%%3A' .. ( adm1st or country.iso_3166 ) .. '&' )
	end

	local html = mw.html.create( 'div' )
		:addClass( 'voy-coord-indicator' )
		:attr( 'data-zoom', zoom )
		:attr( 'data-lat', lat )
		:attr( 'data-lon', long )
		:node( mw.html.create( 'div' )
			:addClass( 'voy-icon' )
			:attr( 'title', c )
			:node( mw.html.create( 'span' )
				:addClass( 'voy-map-globe-default' )
				:wikitext( gi.titles.globeDefault )
			)
			:node( mw.html.create( 'span' )
				:addClass( 'voy-map-globe-js' )
				:css( 'display', 'none' )
				:wikitext( gi.titles.globeJS )
			)
		)
		:node( mw.html.create( 'div' )
			:attr( 'class', 'voy-coords printNoLink plainlinks' )
			:attr( 'title', m )
			:wikitext( inset )
		)

	-- adding country- and region-related data
	if country.id ~= '' then
		if country.cc ~= '' then
			country.trunkPrefix = lp.getTrunkPrefix( country.cc )
		end

		html:attr( 'data-country', data( country.iso_3166 ) )
			:attr( 'data-country-name', data( country.country ) )
			:attr( 'data-adm1st', adm1st )
			:attr( 'data-country-calling-code', data( country.cc ) )
			:attr( 'data-trunk-prefix', data( country.trunkPrefix ) )
			:attr( 'data-lang', data( country.lang ) )
			:attr( 'data-lang-name', data( country.langName ) )
			:attr( 'data-currency', data( country.addCurrency ) )
			:attr( 'data-dir', data( country.isRTL and 'rtl' or 'ltr' ) )
	end

	return tostring( html )
end

-- getLengthFromWD returns a length by property from WD
local function getLengthFromWD( id, p )
	local w = wu.getValue( id, p )
	if w == '' then
		return 0
	end

	local a = tonumber( w.amount ) or 0
	local u = lengthUnits[ w.unit ]
	if u then
		u = u[ 2 ]
	else
		u = wu.getValue( w.unit, gi.properties.conversionToSI )
		u = u == '' and 0 or tonumber( u.amount ) or 0
	end

	return a * u
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 = not isSet( args.lat ) or not isSet( args.long ),
		faultyCoordinate = false,
		distanceErr = 0,
		fromWD = false
	}

	if not coordState.err then
		local objLat = cd.toDec( args.lat, 'lat', 8 )
		args.lat = objLat.dec
		local objLong = cd.toDec( args.long, 'long', 8 )
		args.long = objLong.dec
		coordState.err = ( objLat.error + objLong.error ) > 0
		coordState.faultyCoordinate = coordState.err
	end

	if not args.wikidata then
		return args, coordState
	end

	if not isSet( args.name ) then
		args.name = mw.wikibase.label( args.wikidata ) or ''
	end

	local length = math.abs( tonumber( args.dim ) or 0 )
	if length < 1 then
		length = getLengthFromWD( args.wikidata, gi.properties.length )
		local width = getLengthFromWD( args.wikidata, gi.properties.width )
		if width > length then
			length = width
		end
	end
	args.dim = length < 1 and '' or round( length )

	-- getting coordinates in any case
	local c = wu.getValue( args.wikidata, gi.properties.centerCoordinates )
	if c == '' then
		c = wu.getValue( args.wikidata, gi.properties.coordinates )
	end
	if c ~= '' then
		c.latitude = tonumber( c.latitude )
		c.longitude = tonumber( c.longitude )
		-- 1° ~ 1842 m
		c.precision = ( tonumber( c.precision ) or 0 ) * 1842
		if not isSet( args.prec ) and c.precision >= 1 then
			args.prec = round( c.precision )
		end

		if coordState.err then
			args.lat = c.latitude
			args.long = c.longitude
			coordState.err = false
			coordState.faultyCoordinate = false
			coordState.fromWD = true			
		else
			-- GeoData and Wikidata positions may differ
			coordState.distanceErr = gc.getGcd( args.lat, args.long,
				c.latitude, c.longitude )
		end
	end

	return args, coordState
end

local function makeCoordinates( args, pattern )
	local s, lat, long
	if args.format == 'dec' then
		s, lat, long = cd.getDecGeoLink( pattern, args.lat, args.long, args.precision )
	else
		s, lat, long = cd.getGeoLink( pattern, args.lat, args.long, '', '', '', '',
			args.precision, args.format )
	end
	return s
end

-- Display the coordinates
local function displayCoords( args, frame, isNs0 )
	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.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 isSet( args.wikidata ) or not mw.wikibase.isValidEntityId( args.wikidata ) then
		args.wikidata = nil
	end
	if not scalesByType[ args.type ] then
		args.type  = ''
	end
	local cat      = '' -- tracking categories

	-- Parameter check

	local function fIsInline( s ) -- inline in any case
		return s:find( 'inline' )
			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' ) or s == 't' or s == 'it' or s == 'ti'
	end
	local isInTitle = fIsInTitle( args.display )

	if not isInline and not isInTitle then
		isInline = true
	end

	if isInTitle then
		if not args.wikidata then
			args.wikidata = mw.wikibase.getEntityIdForCurrentPage()
		end
		if not isSet( args.name ) then
			args.name = mw.title.getCurrentTitle().subpageText
		end
	end

	local coordState
	args, coordState = getParamsFromWD( args )
	if coordState.err then
		local m = coordState.faultyCoordinate and gi.errorMsg.faultyCoordinate or ''
		if isInTitle then
			return m .. gi.categories.geoWithoutCoords
		else
			return m .. 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 country = cm.getCountryData( args.wikidata, nil )
	if country.fromWD then
		cat = cat .. gi.categories.countryFromWD
	end
	if not isSet( args.region ) then
		args.region = country.iso_3166
	end

	if args.name == '' then
		args.name = gi.errorMsg.missingName
		cat = cat .. gi.categories.coordWithoutName
	end
	if args.scale == '' and args.type ~= '' then
		args.scale = scalesByType[ args.type ]
	end

	if args.zoom ~= '' then
		args.zoom = round( args.zoom )
		if args.zoom < 0 and args.zoom > maxZoomLevel then
			args.zoom = ''
		end
	end
	if args.dim == '' and args.radius == '' and args.zoom == ''
		and args.scale == '' then
		args.dim = 4000
		cat = cat .. gi.categories.withoutScale
	end

	if args.dim == '' and args.radius ~= '' then
		args.dim = round( 2 * args.radius )
	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.scale == '' then
		args.scale = 5 * args.dim
	end
	args.scale = roundScale( args.scale )

	if args.precision == '' then -- mainly for geo/geoData
		args.precision = getPrecisionFromSize( args.dim, args.prec )
	end

	local extra = getExtraParameters( args )

	local mf = ''
	if args.addMf == 'true' then -- adding microformat
		mf = getMicroformat( args.name, 'listing-coordinates' )
	end

	-- inline coordinates
	local v = ''
	if isInline then
		v = '<span class="printNoLink plainlinks'
			.. '">' .. mf
			.. '[' .. gi.coordURL .. '$1_$2_' .. mw.uri.encode( extra, 'QUERY' )
			.. '&locname=' .. mw.uri.encode( args.name, 'QUERY' )
			.. ' <span class="voy-coord-style" title="' .. gi.titles.latitude .. '">$3</span>'
			.. ' <span class="voy-coord-style" title="' .. gi.titles.longitude .. '">$4</span>]'
			.. '</span>'
		v = makeCoordinates( args, v )
	end

	-- indicator/in title coordinates
	local w = ''
	if isInTitle then
		w = mf
			.. '[' .. gi.coordURL .. '$1_$2_' .. mw.uri.encode( extra, 'QUERY' )
			.. '&locname=' .. mw.uri.encode( args.name, 'QUERY' ) .. ' $3<br />$4]'
		w = makeCoordinates( args, w )
		w = indicatorTable( w, args.name, getZoomFromScale( args.scale ),
			args.lat, args.long, country )
	end

	local parserFc = ''
	local parserFcArgs = { args.lat, args.long, extra, name = args.name }
	if isInTitle then
		table.insert( parserFcArgs, 1, 'primary' )
	end
	if frame and args.addMf == 'true' then -- adding {{#coordinates}}
		parserFc = frame:callParserFunction{ name = '#coordinates',
			args = parserFcArgs }
	end

	v = v .. w .. parserFc .. cat
		.. ( isNs0 and wu.getCategories( gi.categories.properties ) or '' )
	return v
end

-- [[template:Coord]] template
-- format: f1 ... f4, dec
function gd.coord( frame )
	local args     = frame:getParent().args
	local ns       = mw.title.getCurrentTitle().namespace

	args.display   = 'inline'
	args.precision = setValue( args.precision, '4' )
	args.addMf     = 'true'
		-- with {{#coordinates}} and microformat
	
	return displayCoords( args, frame, ns == 0 ) .. gp.checkParams( args, gp.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()
	local ns     = title.namespace
	local categs = ''

	args.display = 'title'
	args.format  = 'f2'
	args.name    = setValue( args.name, title.subpageText )
	args.addMf   = frame.args.minerva and 'false' or 'true'
		-- prevent 2nd #coordinates call with Minerva skin

	if ns == 0 then
		categs = categs .. gi.categories.hasGeo
	end
	return displayCoords( args, frame, ns == 0 )
		.. gp.checkParams( args, gp.geo ) .. categs
end

return gd