Modul:Coordinates: Forskjell mellom sideversjoner
;nb>Tholme (require('strict')) |
m (Én sideversjon ble importert) |
Sideversjonen fra 23. feb. 2024 kl. 11:03

- NO LABEL (P625) (se bruk)
Coordinates er en Lua-modul som formaterer koordinater for visning enten i løpetekst i tittelområdet (minikartet oppe til høyre). Den lager også koordinater til #coordinates-parserfunksjonen.
Modulen henter koordinater fra Wikidata. Hvis koordinater finnes både lokalt og på Wikidata vil modulen sammenligne dem og putte siden i en av kategoriene Kategori:Sider med koordinater som samsvarer med Wikidata (0) eller Kategori:Sider med koordinater som avviker fra Wikidata (0).
Bruk
Eksporte funksjoner :
coordinates.coord(frame)
– formaterer geografiske koordinater for visning enten i løpetekst eller i
statusindikatorområdet (oppe til høyre). Lager også koordinater til #coordinates-parserfunksjonen.
p.dec2dms(frame)
– konverterer koordinater uttrykt i titallsystemet til seksagesimalsystemetp.dms2dec(frame)
– konverterer koordinater uttrykt i seksagesimalsystemet til titallsystemetp.latitude(frame)
– henter ut breddegrad (fra lokale malparametre eller fra Wikidata). Spesielt nyttig for infobokserp.longitude(frame)
– henter ut lengdegrad (fra lokale malparametre eller fra Wikidata). Spesielt nyttig for infobokserp.distance(frame)
– beregner avstanden mellom to punkter
p._coord(args)
– funksjon ála p.coord til bruk i andre Lua-modulerp._dms2dec(dmsobject)
– funksjon ála p.dms2dec til bruk i andre Lua-modulerp._dec2dms(coordtype, precision)
– funksjon ála p.dec2dms til bruk i andre Lua-modulerp._distance(a, b, globe)
– funksjon ála p.distance til bruk i andre Lua-modulerp._parsedmsstring(str, dimension)
- lager en dms-tabell fra en streng av typen "48/22/16/W".
Interne funksjoner:
makeerror
- lager feilmeldingerbuildHTML
- formaterer resultatet for p.coord() som en GeoHack-lenkebuildMaplinkHTML
- formaterer resultatet for p.coord() som en maplink-lenkedisplaydmsdimension
- gjør om en dms-tabell som inneholder grader, minutter, sekunder, himmelretning og koordtype (= breddegrad eller lengdegrad) til en streng av typen 48° 29'32 "Nvaliddms
- sjekker at en dms-tabell er gyldig (gyldig himmelretning og gyldig koordtype, gyldige verdier for grader, minutter og sekunder)builddmsdimension
- lager en dms-tabelldisplaydec
- gjør om en desimalbreddegrad og en desimallengdegrad til en streng av typen "34.294, 12.321"parsedec
- tolker og validerer desimalkoordinaterconvertprcision
- gjør om presisjonen funnet av Module:Math.precision til "d", "dm" eller "dms"convertwikidataprecision
- gjør om presisjonen fra Wikidata til "d", "dm" eller "dms"determinedmsprec
- beregner graden av presisjon som passer best for gitt desimalkoordinaterdec2dms_d
- konverterer et desimalt koordinat til dms med presisjon på gradnivådec2dms_dm
- konverterer et desimalt koordinat til dms med presisjon på minuttnivådec2dms_dms
- konverterer et desimalt koordinat til dms med presisjon på sekundnivåwikidatacoords
- henter koordinater fra Wikidata
Interne variabler:
- wikidatathreshold : For sider som har koordinater både lokalt og på Wikidata: Hvis koordinatene avviker med mer enn denne avstanden (i kilometer),
havner siden i Kategori:Sider med koordinater som avviker fra Wikidata. Ellers havner den i Kategori:Sider med koordinater som samsvarer med Wikidata.
Modulavhengigheter:
Module:Math
– For å håndtere avrunding og presisjon
Grunleggende eksempler
Grunnleggende sett støtter modulen tre måter å angi geografiske koordinater på:
- Med desimalgrader:
{{#invoke:Coordinates | coord |43.651234|-79.383333}}
: 43° 39′ 04″ N, 79° 23′ 00″ V- breddegrad (43.651234) og lengdegrad (-79.383333) til Toronto er angitt som desimaltall
- Med tradisjonell angivelse:
{{#invoke:Coordinates | coord |43|29|4|N|79|23|0|W}}
: 43° 29′ 04″ N, 79° 23′ 00″ V- breddegrad (43/29/4/N) og lengdegrad (79/23/0/W) til Toronto er angitt som grader, (bue)minutter og (bue)sekunder
{{#invoke:Coordinates | coord |43/29/4/N|79/23/0/W}}
: 43° 29′ 04″ N, 79° 23′ 00″ V- breddegrad (43/29/4/N) og lengdegrad (79/23/0/W) til Toronto i én parameter hver
- Fra d:Property:P625 på Wikidata (hvis artikkelsubjektet har flere koordinater brukes det første settet)
- *
{{#invoke:Coordinates | coord | wikidata=true}}
Som standard er utdataformatet det samme som inngangsformatet, men det kan endres ved å sende et ekstra argument |format=xxx
- dms for tradisjonell angivelse med grader, minutter og sekunder
{{#invoke:Coordinates | coord |43.651234|-79.383333|format=dms}}
: 43° 39′ 04″ N, 79° 23′ 00″ V
- dms long for tradisjonell angivelse med grader, minutter og sekunder samt himmelretning fullt utskrevet
{{#invoke:Coordinates | coord |43.651234|-79.383333|format=dms long}}
: 43° 39′ 04″ nord, 79° 23′ 00″ vest
- dec for desimalgrader:
{{#invoke:Coordinates | coord |43|29|4|N|79|23|0|W|format=dec}}
: 43,48444, −79,38333
Valg for funksjonen p.coord
Option de la fonction p.coord (utilisable depuis Lua)
- latitude =
- longitude =
- globe = (planet, hvis annen planet enn jorda)
- format = 'dms', 'dec' eller 'dms long'
- displaytitle = "true" for å vise koordinater i statusindikatorområdet (tittel)
- formattitle = hvis koordinatene i statusindikatorområdet skal ha et bestemt format
- wikidata = "true" for å hente koordinater fra Wikidata
- wikidataprop = Wikidata-egenskap som skal brukes, standard er P625
Detaljerte eksempler
Desimalgrader
Tradisjonell angivelse
Kode | Resultat | Resultat |format=dec |
Resultat |format=dms |
Resultat |format=dms long |
Notes |
---|---|---|---|---|---|
{{#invoke:Coordinates|coord|43|39|N|79|23|W}} | 43° 39′ N, 79° 23′ V | 43,65, −79,383 | 43° 39′ N, 79° 23′ V | 43° 39′ nord, 79° 23′ vest | Toronto, med grader og minutter |
{{#invoke:Coordinates|coord|43|39|4|N|79|23|0|W}} | 43° 39′ 04″ N, 79° 23′ 00″ V | 43,65111, −79,38333 | 43° 39′ 04″ N, 79° 23′ 00″ V | 43° 39′ 04″ nord, 79° 23′ 00″ vest | Toronto, med grader, minutter og sekunder |
{{#invoke:Coordinates|coord|43|39|4.5|N|79|23|0.5|W}} | 43° 39′ 04,5″ N, 79° 23′ 00,5″ V | 43,65125, −79,383472 | 43° 39′ 04,5″ N, 79° 23′ 00,5″ V | 43° 39′ 04,5″ nord, 79° 23′ 00,5″ vest | Toronto, med grader, minutter, sekunder og sekunddeler |
{{#invoke:Coordinates|coord|43/39/N|79/23/W}} | 43° 39′ N, 79° 23′ V | 43,65, −79,383 | 43° 39′ N, 79° 23′ V | 43° 39′ nord, 79° 23′ vest | Toronto, med hvert koordinat samlet i et felt hver |
Ekstra parametre for maplink
Enkelte av de gamle GeoHack-parametrene støttes, men ikke alle.
- Zoomnivå for kartet kan settes enten med
zoom:
(fra 0 til 19).
Alternativt kan type:
brukes med et sett av forhåndsdefinerte verdier (type:city
gir for eksempel zoomnivå 9).
Det gamle GeoHack-argumentet scale:
er også støttet, det konverteres til zoomnivå internt.
Det gamle GeoHack-argumentet dim:
er ikke støttet.
region:
er ikke støttet av maplink (enda???). Det betyr at vi ikke kan brukeregion:NO
for å angi at Norgeskart skal dukke opp i lista over eksterne kart f.eks.- Flere parametre skilles med understrek.
Trykk på lenkene under for å se resultatet av de forskjellige verdiene
Parameter | Eksempel | Resultat | Notes |
---|---|---|---|
{{#invoke:Coordinates|coord|43.65|-79.38}} | 43° 39′ N, 79° 23′ V | Toronto, standardvisning | |
zoom: | {{#invoke:Coordinates|coord|43.65|-79.38|zoom:5}} | 43° 39′ N, 79° 23′ V | Toronto, med zoomnivå 5 for å vise hele landet i kartvisningen |
scale: | {{#invoke:Coordinates|coord|43.65|-79.38|scale:3000000}} | 43° 39′ N, 79° 23′ V | Toronto, med skala 3000000 for å vise hele landet i kartvisningen |
dim: | |||
type: | {{#invoke:Coordinates|coord|43.65|-79.38|type:city}} | 43° 39′ N, 79° 23′ V | Toronto, med en skala som typisk passer for en by (type:city tilsvarer zoomnivå 9) |
region: | Toronto, ved å angi region:CA kan det vises karttjenester som er spesielt tilpasset Canada (ikke støttet) | ||
globe: | {{#invoke:Coordinates|coord|9.7|-20.0|globe:moon}} | 9,7, −20 | Copernicus (månekrater), med kartlag for månen |
name= | {{#invoke:Coordinates|coord|43.65|-79.38|name=Toronto}} | 43° 39′ N, 79° 23′ V | Toronto, med et navn som vises når du trykker på pekeren |
Visning i statusindikatorområdet (tittellinjen)
Bruk |display=
for å endre hvor koordinatene vises:
- {{#invoke:Coordinates|coord|43.65|-79.38|display=inline}} : Vis bare i løpetekst (standard)
- {{#invoke:Coordinates|coord|43.65|-79.38|display=title}} : Vis bare i statusindikatorområdet
- {{#invoke:Coordinates|coord|43.65|-79.38|display=inline,title}} : Vis begge steder
For å vise koordinatene i statusindikatorområdet på et annet format går det an å bruke |formatitle
:
- {{#invoke:Coordinates|coord|43.65|-79.38|display=inline,title|format=dec|formatitle=dms}} : Koordinatene vises som desimalgrader i løpeteksten, men på tradisjonelt format i statusindikatorområdet
Feilmeldinger
Modulen viser en feilmelding hvis parametrene ikke utgjør gyldige koordinater.
- Eksempel på feilaktig bruk
- {{#invoke:Coordinates|coord|2843.65|-79.38}} : Koordinater : ugyldig himmelretning for lengdegrad, må være «E», «Ø», «V» eller «W»
Sider med feilaktig bruk havner i Kategori:Sider med feilaktige koordinattagger.
Bruk av andre funksjoner
Konvertering fra desimalgrader til seksagesimal
{{#invoke:Coordinates | dec2dms | verdi | positiv retning | negativ retning | presisjon}}
- verdi : desimaltall
- positiv retning : positiv himmelretning (N for breddegrad / E for lengdegrad)
- negativ retning : negativ himmelretning (S for breddegrad / W for lengdegrad)
- presisjon : D, DM eller DMS
- Eksempel
{{#invoke:Coordinates|dec2dms|43.651234|N|S|DMS}}
: 43° 39′ 04″ N{{#invoke:Coordinates|dec2dms|43.651234|Ø|V|DM}}
: 43° 39′ Ø
Konvertering fra seksagesimal til desimal
{{#invoke:Coordinates | dms2dec | retning | grader | minutter | sekunder}}
- retning: himmelretning (N/S/V/Ø)
- grader, minutter, sekunder
- Eksempel
{{#invoke:Coordinates|dms2dec|N|43|39|4}}
: 43.65111{{#invoke:Coordinates|dms2dec|N|43|39}}
: 43.65{{#invoke:Coordinates|dms2dec|43/39/4/N}}
: 43.65111{{#invoke:Coordinates|dms2dec|43/39/N}}
: 43.65
Sporingskategorier
- Kategori:Sider med feilaktige koordinattagger (0)
- Kategori:Sider med koordinater som samsvarer med Wikidata (0)
- Kategori:Sider med koordinater som avviker fra Wikidata (0)
- Kategori:Sider med koordinater som mangler på Wikidata (0)
- Kategori:Sider med koordinater fra Wikidata (0)
require('strict') local math_mod = require( "Module:Math" ) local p = {} local i18n = { N = 'N', Nlong = 'nord', W = 'V', Wlong = 'vest', E = 'Ø', Elong = 'øst', S = 'S', Slong = 'sør', degrees = '° ', minutes = '′ ', seconds = '″ ', geohackurl = 'http://tools.wmflabs.org/geohack/geohack.php?language=nb', tooltip = 'Kart, flyfoto m.m.', errorcat = 'Sider med feilaktige koordinattagger', sameaswikidata = 'Sider med koordinater som samsvarer med Wikidata', notaswikidata = 'Sider med koordinater som avviker fra Wikidata', nowikidata = 'Sider med koordinater som mangler på Wikidata', throughwikidata = 'Sider med koordinater fra Wikidata', invalidFormat = 'ugyldig format ', -- 'invalid coordinate format', invalidNSEW = 'ugyldig himmelretning, må være «N», «S», «E», «Ø», «W» eller «V»', -- 'invalid direction should be "N", "S", "E" or "W"', invalidNS = 'ugyldig himmelretning for breddegrad, må være «N» eller «S»', -- 'could not find latitude direction (should be N or S)', invalidEW = 'ugyldig himmelretning for lengdegrad, må være «E», «Ø», «V» eller «W»', -- 'could not find longitude direction (should be W or E) ', noCardinalDirection = 'mangler himmelretning', -- 'no cardinal direction found in coordinates', invalidDirection = 'ugyldig himmelretning', -- 'invalid direction', latitude90 = 'breddegrad > 90', longitude360 = 'lengdegrad > 360', minSec60 = 'minutter eller sekunder > 60', negativeCoode = 'dms-koordinater skal ikke være negative', -- 'dms coordinates should be positive', dmIntergers = 'grader og minutter må være tall', -- 'degrees and minutes should be integers', tooManyParam = 'for mange parametere', -- 'too many parameters for coordinates', coordMissing = 'mangler lengdegrad eller breddegrad', -- 'latitude or longitude missing', invalidGlobe = 'ugyldig globe : ', -- 'invalid globe:', } local coordParse = { ['Ø'] = 'E', ['V'] = 'W', } local globedata = { --[[ notes: radius in kilometers (especially imprecise for non spheric bodies) defaultdisplay is currently disabled, activate it ? ]]-- ariel = {radius = 580, defaultdisplay = 'dec east'}, callisto = {radius = 2410, defaultdisplay = 'dec west'}, ceres = {radius = 470, defaultdisplay = 'dec east'}, charon = {radius = 1214, defaultdisplay = 'dec east'}, deimos = {radius = 7, defaultdisplay = 'dec west'}, dione = {radius = 560, defaultdisplay = 'dec west'}, enceladus = {radius = 255, defaultdisplay = 'dec west'}, ganymede = {radius = 2634, defaultdisplay = 'dec west'}, earth = {radius = 6371, defaultdisplay = 'dms'}, europa = {radius = 1561, defaultdisplay = 'dec east'}, hyperion = {radius = 140, defaultdisplay = 'dec west'}, iapetus = {radius = 725, defaultdisplay = 'dec west'}, ['io'] = {radius = 1322, defaultdisplay = 'dec west'}, jupiter = {radius = 68911, defaultdisplay = 'dec east'}, mars = {radius = 3389.5, defaultdisplay = 'dec east' }, mercury = {radius = 2439.7, defaultdisplay = 'dec west'}, mimas = {radius = 197, defaultdisplay = 'dec west'}, miranda = {radius = 335, defaultdisplay = 'dec east'}, moon = {radius = 1736, defaultdisplay = 'dec'}, neptune = {radius = 24553, defaultdisplay = 'dec east'}, oberon = {radius = 761, defaultdisplay = 'dec east'}, phoebe = {radius = 110, defaultdisplay = 'dec west'}, phobos = {radius = 11, defaultdisplay = 'dec west'}, pluto = {radius = 1185, defaultdisplay = 'dec east'}, rhea = {radius = 765, defaultdisplay = 'dec west'}, saturn = {radius = 58232, defaultdisplay = 'dec east'}, titan = {radius = 2575.5, defaultdisplay = 'dec west'}, tethys = {radius = 530, defaultdisplay = 'dec west'}, titania = {radius = 394, defaultdisplay = 'dec east'}, triton = {radius = 1353, defaultdisplay = 'dec east'}, umbriel = {radius = 584, defaultdisplay = 'dec east'}, uranus = {radius = 25266, defaultdisplay = 'dec east'}, venus = {radius = 6051.8, defaultdisplay = 'dec east'}, vesta = {radius = 260, defaultdisplay = 'dec east'} } globedata[''] = globedata.earth local wikidataglobes = { -- maps Wikidata items used in coordinate-types properties of Wikidata to globe names as used by geohack ['http://www.wikidata.org/entity/Q3343'] = 'ariel', ['http://www.wikidata.org/entity/Q3134'] = 'callisto', ['http://www.wikidata.org/entity/Q596'] = 'ceres', ['http://www.wikidata.org/entity/Q6604'] = 'charon', ['http://www.wikidata.org/entity/Q7548'] = 'deimos', ['http://www.wikidata.org/entity/Q15040'] = 'dione', ['http://www.wikidata.org/entity/Q2'] = 'earth', ['http://www.wikidata.org/entity/Q3303'] = 'enceladus', ['http://www.wikidata.org/entity/Q3143'] = 'europa', ['http://www.wikidata.org/entity/Q3169'] = 'ganymede', ['http://www.wikidata.org/entity/Q15037'] = 'hyperion', ['http://www.wikidata.org/entity/Q17958'] = 'iapetus', ['http://www.wikidata.org/entity/Q3123'] = 'io', ['http://www.wikidata.org/entity/Q319'] = 'jupiter', ['http://www.wikidata.org/entity/Q111'] = 'mars', ['http://www.wikidata.org/entity/Q308'] = 'mercury', ['http://www.wikidata.org/entity/Q15034'] = 'mimas', ['http://www.wikidata.org/entity/Q3352'] = 'miranda', ['http://www.wikidata.org/entity/Q405'] = 'moon', ['http://www.wikidata.org/entity/Q332'] = 'neptune', ['http://www.wikidata.org/entity/Q3332'] = 'oberon', ['http://www.wikidata.org/entity/Q7547'] = 'phobos', ['http://www.wikidata.org/entity/Q17975'] = 'phoebe', ['http://www.wikidata.org/entity/Q339'] = 'pluto', ['http://www.wikidata.org/entity/Q15050'] ='rhea', ['http://www.wikidata.org/entity/Q193'] = 'saturn', ['http://www.wikidata.org/entity/Q15047'] = 'tethys', ['http://www.wikidata.org/entity/Q2565'] = 'titan', ['http://www.wikidata.org/entity/Q3322'] = 'titania', ['http://www.wikidata.org/entity/Q3359'] = 'triton', ['http://www.wikidata.org/entity/Q3338'] = 'umbriel', ['http://www.wikidata.org/entity/Q324'] = 'uranus', ['http://www.wikidata.org/entity/Q313'] = 'venus', ['http://www.wikidata.org/entity/Q3030'] ='vesta', } local wikidatathreshold = 10 -- si la distance entre coordonnées Wikipédia et Wikidata dépasse se seuil (en kilomètes), une catégorie de maintenance est ajoutée local lang = mw.language.getContentLanguage() local default_zoom = 13 local function makecat(cat, sortkey) if type( sortkey ) == 'string' then return '[[Category:' .. cat .. '|' .. sortkey .. ']]' else return '[[Category:' .. cat .. ']]' end end ---------------------------------------- --Error handling --[[ Notes: when errors occure a new error message is concatenated to errorstring an error message contains an error category with a sortkey For major errors, it can also display an error message (the error message will the usually be returned and the function terminated) More minor errors do only add a category, so that readers are not bothered with error texts sortkeys: * A: invalid latitude, longitude or direction * B: invalid globe * C: something wrong with other parameters * D: more than one primary coord ]]-- local errorstring = '' local function makeerror(args) local errormessage = '' if args.message then errormessage = '<strong class="error"> Koordinater : ' .. args.message .. '</strong>' end local errorcat = '' if mw.title.getCurrentTitle().namespace == 0 then errorcat = makecat(i18n.errorcat, args.sortkey) end errorstring = errormessage .. errorcat -- reinitializes the string to avoid absurdly long messages return nil end local function showerrors() return errorstring end -- Distance computation function p._distance(a, b, globe) -- calcule la [[distance orthodromique]] en kilomètres entre deux points du globe globe = string.lower(globe or 'earth') -- check arguments and converts degreees to radians local latA, latB, longA, longB = a.latitude, b.latitude, a.longitude, b.longitude if (not latA) or (not latB) or (not longA) or (not longB) then return error('coordinates missing, can\'t compute distance') end if type(latA) ~= 'number' or type(latB) ~= 'number' or type(longA) ~= 'number' or type(longB) ~= 'number' then error('coordinates are not numeric, can\'t compute distance') end if not globe or not globedata[globe] then return error('globe: ' .. globe .. 'is not supported') end -- calcul de la distance angulaire en radians local convratio = math.pi / 180 -- convertit en radians latA, latB, longA, longB = convratio * latA, convratio * latB, convratio * longA, convratio * longB local cosangle = math.sin(latA) * math.sin(latB) + math.cos(latA) * math.cos(latB) * math.cos(longB - longA) if cosangle >= 1 then -- may be above one because of rounding errors return 0 end local angle = math.acos(cosangle) -- calcul de la distance en km local radius = globedata[globe].radius return radius * angle end function p.distance(frame) local args = frame.args return p._distance( {latitude = tonumber(args.latitude1), longitude = tonumber(args.longitude1)}, {latitude = tonumber(args.latitude2), longitude = tonumber(args.longitude2)}, args.globe) end local function geoHackUrl(decLat, decLong, globe, displayformat, objectname, extraparams) extraparams = extraparams or '' local geohacklatitude, geohacklongitude -- format latitude and longitude for the URL if tonumber(decLat) < 0 then geohacklatitude = tostring(-tonumber(decLat)) .. '_S' else geohacklatitude = decLat .. '_N' end if tonumber(decLong) < 0 then geohacklongitude = tostring(-tonumber(decLong)) .. '_W' elseif globedata[globe].defaultdisplay == 'dec west' then geohacklongitude = decLong .. '_W' else geohacklongitude = decLong .. '_E' end -- prepares the 'paramss=' parameter local geohackparams = geohacklatitude .. '_' .. geohacklongitude .. '_' ..extraparams -- concatenate parameteres for geohack return i18n.geohackurl .. "&pagename=" .. mw.uri.encode(mw.title.getCurrentTitle().prefixedText, "WIKI") .. "¶ms=" .. geohackparams .. (objectname and ("&title=" .. mw.uri.encode(objectname)) or "") end --HTML builder for a geohack link local function buildHTML(decLat, decLong, dmsLat, dmsLong, globe, displayformat, displayinline, displaytitle, objectname, extraparams) -- geohack url local url = geoHackUrl(decLat, decLong, globe, displayformat, objectname, extraparams) -- displayed coordinates local displaycoords if string.sub(displayformat,1,3) == 'dec' then displaycoords = p.displaydec(decLat, decLong, displayformat) else displaycoords = { p.displaydmsdimension(dmsLat, displayformat), p.displaydmsdimension(dmsLong, displayformat), } end -- build coordinate in h-geo / h-card microformat local globeNode if globe and globe ~= 'earth' then globeNode = mw.html.create('data') :addClass('p-globe') :attr{ value = globe } :done() end local coordNode = mw.html.create('') if objectname then coordNode = mw.html.create('span') :addClass('h-card') :tag('data') :addClass('p-name') :attr{ value = objectname } :done() end coordNode :tag('span') :addClass('h-geo') :addClass('geo-' .. string.sub(displayformat,1,3)) :tag('data') :addClass('p-latitude') :attr{ value = decLat } :wikitext( displaycoords[1] ) :done() :wikitext(", ") :tag('data') :addClass('p-longitude') :attr{ value = decLong } :wikitext( displaycoords[2] ) :done() :node( globeNode ) :done() -- buid GeoHack link local root = mw.html.create('span') :addClass('plainlinks nourlexpansion') :attr('title', i18n.tooltip) :wikitext('[' .. url ) :node(coordNode) :wikitext("]") :done() -- format result depending on args["display"] (nil, "inline", "title", "inline,title") local inlineText = displayinline and tostring(root) or '' local titleText = '' if displaytitle then local htmlTitle = mw.html.create('span') :attr{ id = 'coordinates' } :addClass( displayinline and 'noprint' or nil ) :node( root ) local frame = mw.getCurrentFrame() titleText = frame:extensionTag( 'indicator', tostring(htmlTitle), { name = 'coordinates' } ) end return inlineText .. titleText end local function zoom( extraparams ) local zoomParam = extraparams:match( '%f[%w]zoom: ?(%d+)' ) if zoomParam then return zoomParam end local scale = extraparams:match( '%f[%w]scale: ?(%d+)' ) if scale then return math.floor(math.log10( 1 / tonumber( scale ) ) * 3 + 25) end local extraType = extraparams:match( '%f[%w]type: ?(%w+)' ) if extraType then local zoomType = { country = 5, state = 6, adm1st = 7, adm2nd = 8, city = 9, isle = 10, mountain = 10, waterbody = 10, airport = 12, landmark = 13, } return zoomType[ extraType ] end end --HTML builder for a geohack link local function buildMaplinkHTML( decLat, decLong, dmsLat, dmsLong, globe, displayformat, displayinline, displaytitle, objectname, extraparams ) -- displayed coordinates local displaycoords if string.sub(displayformat,1,3) == 'dec' then displaycoords = p.displaydec(decLat, decLong, displayformat) else displaycoords = { p.displaydmsdimension(dmsLat, displayformat), p.displaydmsdimension(dmsLong, displayformat), } end -- JSON for maplink local jsonParams = { type = 'Feature', geometry = { type ='Point', coordinates = { math_mod._round( decLong, 6 ), -- max precision in GeoJSON format math_mod._round( decLat, 6 ) } }, properties = { ['marker-color'] = "228b22", } } if objectname then jsonParams.properties.title = objectname end -- ajout de geoshape via externaldata local geoshape = extraparams:match( '%f[%w]geoshape: ?(Q%d+)' ) if not geoshape and displaytitle and mw.wikibase.getEntity() then geoshape = mw.wikibase.getEntity().id end if geoshape then jsonParams = { jsonParams, { type = 'ExternalData', service = 'geoshape', ids = geoshape, properties = { ['fill-opacity'] = 0.2 } } } end local maplink = mw.getCurrentFrame():extensionTag{ name = 'maplink', content = mw.text.jsonEncode( jsonParams ), args = { text = displaycoords[1] .. ", " .. displaycoords[2], zoom = zoom( extraparams ) or default_zoom, latitude = decLat, longitude = decLong, } } -- format result depending on args["display"] (nil, "inline", "title", "inline,title") local inlineText = displayinline and maplink or '' local titleText = '' if displaytitle then local htmlTitle = mw.html.create('span') :attr{ id = 'coordinates' } :addClass( displayinline and 'noprint' or nil ) :wikitext( maplink ) local frame = mw.getCurrentFrame() titleText = frame:extensionTag( 'indicator', tostring(htmlTitle), { name = 'coordinates' } ) end return inlineText .. titleText end -- dms specific funcions local function twoDigit( value ) if ( value < 10 ) then value = '0' .. lang:formatNum( value ) else value = lang:formatNum( value ) end return value end function p.displaydmsdimension(valuetable, format) -- formate en latitude ou une longitude dms local str = '' local direction = valuetable.direction local degrees, minutes, seconds = '', '', '' local dimension if format == 'dms long' then direction = i18n[direction .. 'long'] else direction = i18n[direction] end degrees = lang:formatNum( valuetable.degrees ) .. i18n.degrees if valuetable.minutes then minutes = twoDigit( valuetable.minutes ) .. i18n.minutes end if valuetable.seconds then seconds = twoDigit( valuetable.seconds ) .. i18n.seconds end return degrees .. minutes .. seconds .. direction end local function validdms(coordtable) local direction = coordtable.direction local degrees = coordtable.degrees or 0 local minutes = coordtable.minutes or 0 local seconds = coordtable.seconds or 0 local dimension = coordtable.dimension if not dimension then if direction == 'N' or direction == 'S' then dimension = 'latitude' elseif direction == 'E' or direction == 'W' then dimension = 'longitude' else makeerror({message = i18n.invalidNSEW, sortkey = 'A'}) return false end end if type(degrees) ~= 'number' or type(minutes) ~= 'number' or type(seconds) ~= 'number' then makeerror({message = i18n.invalidFormat, sortkey = 'A'}) return false end if dimension == 'latitude' and direction ~= 'N' and direction ~= 'S' then makeerror({message = i18n.invalidNS, sortkey = 'A'}) return false end if dimension == 'longitude' and direction ~= 'W' and direction ~= 'E' then makeerror({message = i18n.invalidEW, sortkey = 'A'}) return false end if dimension == 'latitude' and degrees > 90 then makeerror({message = i18n.latitude90, sortkey = 'A'}) return false end if dimension == 'longitude' and degrees > 360 then makeerror({message = i18n.longitude360, sortkey = 'A'}) return false end if degrees < 0 or minutes < 0 or seconds < 0 then makeerror({message = i18n.negativeCoode, sortkey = 'A'}) return false end if minutes > 60 or seconds > 60 then makeerror({message = i18n.minSec60, sortkey = 'A'}) return false end if (math.floor(degrees) ~= degrees and minutes ~= 0) or (math.floor(minutes) ~= minutes and seconds ~= 0) then makeerror({message = i18n.dmIntergers, sortkey = 'A'}) return false end return true end local function builddmsdimension(degrees, minutes, seconds, direction, dimension) -- no error checking, done in function validdms local dimensionobject = {} -- direction and dimension (= latitude or longitude) dimensionobject.direction = direction if dimension then dimensionobject.dimension = dimension elseif direction == 'N' or direction == 'S' then dimensionobject.dimension = 'latitude' elseif direction == 'E' or direction == 'W' then dimensionobject.dimension = 'longitude' end -- degrees, minutes, seconds dimensionobject.degrees = tonumber(degrees) dimensionobject.minutes = tonumber(minutes) dimensionobject.seconds = tonumber(seconds) if degrees and not dimensionobject.degrees then dimensionobject.degrees = 'error' end if minutes and not dimensionobject.minutes then dimensionobject.minutes = 'error' end if seconds and not dimensionobject.seconds then dimensionobject.seconds = 'error' end return dimensionobject end function p._parsedmsstring( str, dimension ) -- prend une séquence et donne des noms aux paramètres -- output table: { latitude=, longitude = , direction = } if type( str ) ~= 'string' then return nil end str = mw.ustring.gsub( mw.ustring.upper( str ), '%a+', coordParse ) if not tonumber( str ) and not str:find( '/' ) and str:find( '°' ) then local str2 = mw.ustring.gsub( str, '[°″′\"\'\194\160 ]+', '/' ) -- avoid cases were there is degree ans seconds but no minutes if not mw.ustring.find( str, '[″"]' ) or mw.ustring.find( str, '%d[′\'][ \194\160%d]' ) then str = str2 end end if not tonumber(str) and not string.find(str, '/') then makeerror({message = i18n.invalidFormat, sortkey= 'A'}) return nil end local args = mw.text.split(str, '/', true) if #args > 4 then makeerror({message = i18n.tooManyParam, sortkey= 'A' }) end local direction = mw.text.trim(args[#args]) table.remove(args) local degrees, minutes, seconds = args[1], args[2], args[3] local dimensionobject = builddmsdimension(degrees, minutes, seconds, direction, dimension) if validdms(dimensionobject) then return dimensionobject else return nil end end --- decimal specific functions function p.displaydec(latitude, longitude, format) local lat = lang:formatNum( latitude ) local long = lang:formatNum( longitude ) if format == 'dec west' or format == 'dec east' then local symbolNS, symbolEW = i18n.N, i18n.E if latitude < 0 then symbolNS = i18n.S lat = lat:sub( 2 ) end if format == 'dec west' then symbolEW = i18n.W end if longitude < 0 then long = lang:formatNum( 360 + longitude ) end return { lat .. i18n.degrees .. symbolNS, long .. i18n.degrees .. symbolEW } else return { lat, long } end end local function parsedec(dec, coordtype, globe) -- coordtype = latitude or longitude dec = mw.text.trim(dec) if not dec then return nil end if coordtype ~= 'latitude' and coordtype ~= 'longitude' then makeerror({'invalid coord type', sortkey = "A"}) return nil end local numdec = tonumber(dec) -- numeric value, kept separated as it looses significant zeros if not numdec then -- tries the decimal + direction format dec = mw.ustring.gsub( mw.ustring.upper( dec ), '%a+', coordParse ) local direction = mw.ustring.sub(dec, mw.ustring.len(dec), mw.ustring.len(dec)) dec = mw.ustring.sub(dec, 1, mw.ustring.len(dec)-2) -- removes the /N at the end if not dec or not tonumber(dec) then return nil end if direction == 'N' or direction == 'E' or direction == 'W' and globedata[globe].defaultdisplay == 'dec west' then numdec = tonumber( dec ) elseif direction == 'W' or direction == 'S' then dec = '-' .. dec numdec = tonumber( dec ) else if coordtype == 'latitude' then makeerror({message = i18n.invalidNS, sortkey = 'A'}) else makeerror({message = i18n.invalidEW, sortkey = 'A'}) end return nil end end if coordtype == 'latitude' and math.abs(numdec) > 90 then makeerror({message = i18n.latitude90 , sortkey = 'A'}) return nil end if coordtype == 'longitude' and math.abs(numdec) > 360 then makeerror({message = i18n.longitude360 , sortkey = 'A'}) return nil end return dec end -- dms/dec conversion functions local function convertprecision(precision) -- converts a decimal precision like "2" into "dm" if precision >= 3 then return 'dms' elseif precision >=1 then return 'dm' else return 'd' end end local function determinedmsprec(decs) -- returns the most precision for a dec2dms conversion, depending on the most precise value in the decs table local precision = 0 for d, val in ipairs(decs) do precision = math.max(precision, math_mod._precision(val)) end return convertprecision(precision) end local function dec2dms_d(dec) local degrees = math_mod._round( dec, 0 ) return degrees end local function dec2dms_dm(dec) dec = math_mod._round( dec * 60, 0 ) local minutes = dec % 60 dec = math.floor( (dec - minutes) / 60 ) local degrees = dec % 360 return degrees, minutes end local function dec2dms_dms(dec) dec = math_mod._round( dec * 60 * 60, 0 ) local seconds = dec % 60 dec = math.floor( (dec - seconds) / 60 ) local minutes = dec % 60 dec = math.floor( (dec - minutes) / 60 ) local degrees = dec % 360 return degrees, minutes, seconds end function p._dec2dms(dec, coordtype, precision, globe) -- coordtype: latitude or longitude local degrees, minutes, seconds -- vérification du globe if not ( globe and globedata[ globe ] ) then globe = 'earth' end -- precision if not precision or precision == '' then precision = determinedmsprec({dec}) end if precision ~= 'd' and precision ~= 'dm' and precision ~= 'dms' then return makeerror({sortkey = 'C'}) end local dec = tonumber(dec) -- direction local direction if coordtype == 'latitude' then if dec < 0 then direction = 'S' else direction = 'N' end elseif coordtype == 'longitude' then if dec < 0 or globedata[globe].defaultdisplay == 'dec west' then direction = 'W' else direction = 'E' end end -- conversion dec = math.abs(dec) -- les coordonnées en dms sont toujours positives if precision == 'dms' then degrees, minutes, seconds = dec2dms_dms(dec) elseif precision == 'dm' then degrees, minutes = dec2dms_dm(dec) else degrees = dec2dms_d(dec) end return builddmsdimension(degrees, minutes, seconds, direction) end function p.dec2dms(frame) -- legacy function somewhat cumbersome syntax local args = frame.args local dec = args[1] if not tonumber(dec) then makeerror({message = i18n.invalidFormat, sortkey = 'A'}) return showerrors() end local dirpositive = string.lower(args[2] or '') local dirnegative = string.lower(args[3] or '') local precision = string.lower(args[4] or '') local displayformat, coordtype if dirpositive == 'n' or dirpositive == 'nord' then coordtype = 'latitude' else coordtype = 'longitude' end if dirpositive == 'nord' or dirpositive == 'est' or dirnegative == 'ouest' or dirnegative == 'sud' then displayformat = 'dms long' end local coordobject = p._dec2dms(dec, coordtype, precision) if coordobject then return p.displaydmsdimension(coordobject, displayformat) .. showerrors() else return showerrors() end end function p._dms2dec(dmsobject) -- transforme une table degré minute secondes en nombre décimal local direction, degrees, minutes, seconds = dmsobject.direction, dmsobject.degrees, dmsobject.minutes, dmsobject.seconds local factor = 0 local precision = 0 if not minutes then minutes = 0 end if not seconds then seconds = 0 end if direction == "N" or direction == "E" then factor = 1 elseif direction == "W" or direction == "S" then factor = -1 elseif not direction then makeerror({message = i18n.noCardinalDirection, sortkey = 'A'}) return nil else makeerror({message = i18n.invalidDirection, sortkey = 'A'}) return nil end if dmsobject.seconds then -- vérifie la précision des données initiales precision = 5 + math.max( math_mod._precision(tostring(seconds), 0 ) ) -- passage par des strings assez tarabiscoté ? elseif dmsobject.minutes then precision = 3 + math.max( math_mod._precision(tostring(minutes), 0 ) ) else precision = math.max( math_mod._precision(tostring(degrees), 0 ) ) end local decimal = factor * (degrees+(minutes+seconds/60)/60) return math_mod._round(decimal, precision) end function p.dms2dec(frame) -- legacy function, somewhat bizarre syntax local args = frame.args if tonumber(args[1]) then return args[1] -- coordonnées déjà en décimal elseif not args[2] then local dmsobject = p._parsedmsstring(args[1]) if dmsobject then return p._dms2dec(dmsobject) -- coordonnées sous la fore 23/22/N else local coordType if args[1]:match( '[NS]' ) then coordType = 'latitude' elseif args[1]:match( '[EWO]') then coordType = 'longitude' end if coordType then local result = parsedec( args[1], coordType, args.globe or 'earth' ) if result then return result end end return showerrors() end else return p._dms2dec({direction = args[1], degrees = tonumber(args[2]), minutes = tonumber(args[3]), seconds = tonumber(args[4])}) end end -- Wikidata local function convertwikidataprecision(precision) -- converts a decima like "0.1" into "dm" if precision < 0.016 then return 'dms' elseif precision < 1 then return 'dm' else return 'd' end end local function wikidatacoords(property) -- gets coordinates from wikidata property = property or 'P625' property = mw.ustring.upper(property) local entity = mw.wikibase.getEntityObject() if entity and entity.claims and entity.claims[property] and entity.claims[property][1] and entity.claims[property][1].mainsnak and entity.claims[property][1].mainsnak.snaktype == 'value' and entity.claims[property][1].mainsnak.datavalue then local coords = entity.claims[property][1].mainsnak.datavalue.value return coords.latitude, coords.longitude, wikidataglobes[coords.globe], convertwikidataprecision(coords.precision or .001) end return nil end -- main function for displaying coordinates function p._coord(args) -- I declare variable local displayformat = args.format -- string: one of: 'dms', 'dms long', 'dec', 'dec east' and 'dec west' local displayplace = string.lower(args.display or 'inline') --string: one of 'inline', 'title' or 'inline,title' local objectname = (args.name ~= '') and args.name -- string: name of the title displayed in geohack local notes = (' ' and args.notes) or '' -- string: notes to de displayed after coordinates local wikidata = args.wikidata -- string: set to "true" if needed local wikidataprop = args.wikidataprop -- Wikidata property to use, defaults to P625 local dmslatitude, dmslongitude -- table (when created) local extraparams = args.extraparams or '' -- string (legacy, corresponds to geohackparams) local trackingstring = '' -- tracking cats except error cats (already in errorstring) local rawlat, rawlong = args.latitude, args.longitude if rawlat == '' then rawlat = nil end if rawlong == '' then rawlong = nil end local globe = string.lower( args.globe or extraparams:match('globe:(%a+)') or '' ) -- string: see the globedata table for accepted values local latitude, longitude, precision, dmslatitude, dmslongitude -- latitude and longitude in decimal / dmslatitude and dmslongitude: tables withdms coords local maplink = true -- use maplink whenever it is possible -- II extract coordinates from Wikitext if (rawlat or rawlong) then if (not rawlat) or (not rawlong) then -- if latitude is provided so should be longitude makeerror({message = i18n.coordMissing, sortkey = 'A'}) return showerrors() end latitude = parsedec(rawlat, 'latitude', globe) if latitude then -- if latitude is decimal longitude = parsedec(rawlong, 'longitude', globe) -- so should be longitude precision = determinedmsprec({latitude, longitude}) -- before conversion from string to number for trailing zeros if not latitude or not longitude then if errorstring == '' then makeerror({message = i18n.invalidFormat, sortkey = 'A'}) end return showerrors() end dmslatitude, dmslongitude = p._dec2dms(latitude, 'latitude', precision), p._dec2dms(longitude, 'longitude', precision, globe) latitude, longitude = tonumber(latitude), tonumber(longitude) else -- if latitude is not decimal try to parse it as a dms string dmslatitude, dmslongitude = p._parsedmsstring(args.latitude, 'latitude'), p._parsedmsstring(args.longitude, 'longitude') if not dmslatitude or not dmslongitude then return showerrors() end latitude, longitude = p._dms2dec(dmslatitude), p._dms2dec(dmslongitude) end end -- III extract coordinate data from Wikidata and compare them to local data local wikidatalatitude, wikidatalongitude, wikidataglobe, wikidataprecision if wikidata == 'true' then wikidatalatitude, wikidatalongitude, wikidataglobe, wikidataprecision = wikidatacoords(wikidataprop) if wikidatalatitude and latitude and longitude then local maxdistance = tonumber(args.maxdistance) or wikidatathreshold if p._distance({latitude = latitude, longitude= longitude}, {latitude = wikidatalatitude, longitude= wikidatalongitude}, wikidataglobe) < maxdistance then trackingstring = trackingstring .. makecat(i18n.sameaswikidata) else trackingstring = trackingstring .. makecat(i18n.notaswikidata) end end if wikidatalatitude and not latitude then latitude, longitude, globe, precision = wikidatalatitude, wikidatalongitude, wikidataglobe, wikidataprecision dmslatitude, dmslongitude = p._dec2dms(latitude, 'latitude', precision), p._dec2dms(longitude, 'longitude', precision, globe) trackingstring = trackingstring .. makecat(i18n.throughwikidata) end if latitude and not wikidatalatitude then if mw.title.getCurrentTitle().namespace == 0 then trackingstring = trackingstring .. makecat(i18n.nowikidata) end end end -- exit if stil no latitude or no longitude if not latitude and not longitude then return nil -- ne rien ajouter ici pour que l'appel à cette fonction retourne bien nil en l'absence de données end -- IV best guesses for missing parameters --- globe if globe == '' then globe = 'earth' end if not globedata[globe] then makeerror({message = i18n.invalidGlobe .. globe}) globe = 'earth' end if globe ~= 'earth' then extraparams = extraparams .. '_globe:' .. globe -- pas de problème si le globe est en double maplink = false end --- diplayformat if not displayformat or displayformat == '' then displayformat = globedata[globe].defaultdisplay end -- displayinline/displaytitle local displayinline = string.find(displayplace, 'inline') local displaytitle = string.find(displayplace, 'title') if not displayinline and not displaytitle then displayinline = true if displayplace ~= '' then makeerror({sortkey = 'C'}) --error if display not empty, but not not a major error, continue end end -- V geodata local geodata = '' if latitude and longitude then local latstring, longstring = tostring(latitude), tostring(longitude) local primary = '' local frame = mw.getCurrentFrame() local geodataparams = {[1] = latstring, [2] = longstring, [3] = extraparams } if displaytitle then geodataparams[4] = 'primary' end if objectname then geodataparams.name = objectname end geodata = frame:callParserFunction('#coordinates', geodataparams ) if string.find(geodata, 'error') then -- the only error that has not been caught yet is primary key geodata = '' makeerror({sortkey='D'}) end end -- VI final output local mainstring = '' if maplink then mainstring = buildMaplinkHTML(latitude, longitude, dmslatitude, dmslongitude, globe, displayformat, displayinline, displaytitle, objectname,extraparams ) else mainstring = buildHTML(latitude, longitude, dmslatitude, dmslongitude, globe, displayformat, displayinline, displaytitle, objectname,extraparams ) end return mainstring .. notes .. trackingstring .. geodata .. showerrors() end function p.coord(frame) -- parrses the strange parameters of Template:Coord before sending them to p.coord local args = frame.args local numericargs = {} for i, j in ipairs(args) do args[i] = mw.text.trim(j) if type(i) == 'number' and args[i] ~= '' then table.insert(numericargs, args[i]) end end if #numericargs %2 == 1 then -- if the number of args is odd, the last one provides formatting parameters args.extraparams = numericargs[#numericargs] if #numericargs == 1 and tonumber(numericargs[1]) then makeerror({message = i18n.coordMissing, sortkey = 'A'}) return showerrors() end table.remove(numericargs) end for i, j in ipairs(numericargs) do if i <= (#numericargs / 2) then if not args.latitude then args.latitude = j else args.latitude = args.latitude .. '/' .. j end else if not args.longitude then args.longitude = j else args.longitude = args.longitude .. '/' .. j end end end if string.find(args.latitude or '', 'E') or string.find(args.latitude or '', 'W') then args.latitude, args.longitude = args.longitude, args.latitude end return p._coord(args) end function p.Coord(frame) return p.coord(frame) end function p.latitude(frame) -- helper function pour infobox, à déprécier local args = frame.args local latitude = frame.args[1] if latitude and mw.text.trim(latitude) ~= '' then return latitude elseif frame.args['wikidata'] == 'true' then local lat, long = wikidatacoords() return lat end end function p.longitude(frame) -- helper function pour infobox, à déprécier local args = frame.args local longitude = frame.args[1] if longitude and mw.text.trim(longitude) ~= '' then return longitude elseif frame.args['wikidata'] == 'true' then local lat, long = wikidatacoords() return long end end return p