Module:Sandbox/Wnt/FindFeatures/displayDatabase
< Module:Sandbox | Wnt | FindFeatures
Documentation for this module may be created at Module:Sandbox/Wnt/FindFeatures/displayDatabase/doc
-- This module finds features with coordinates in a certain area on a globe.
-- current focus is Mars. Earth, celestial, etc. would be nice also.
-- all three dimensionality is hereby banned from the procedure on account of requiring far too much intelligence to get working.
local getArgs = require('Module:Arguments').getArgs
local p = {}
debuglog=""
function tidyNum(text)
text = mw.ustring.gsub(text, " ", "")
text = mw.ustring.gsub(text, ",", ".")
return tonumber(text)
end
function parseValue(text)
-- extract 3 or 2 or 1 values from the string. Can contain . or , as a decimal, no spaces allowed.
local d, m, s = mw.ustring.match(text,"(%-?%d+[%.,]?%d*)[%a%c%s%z!@#$%%^&%*%(%)%=|\~']+(%-?%d+[%.,]?%d*)[%a%c%s%z!@#$%%^&%*%(%)%=|\~']+(%-?%d+[%.,]?%d*)")
if not d then d, m = mw.ustring.match(text,"(%-?%d+[%.,]?%d*)[%a%c%s%z!@#$%%^&%*%(%)%=|\~']+(%-?%d+[%.,]?%d*)") end
if not d then d = mw.ustring.match(text,"(%-?%d+[%.,]?%d*)") end
if d then
d = tidyNum(d or "0") + tidyNum(m or "0")/60 + tidyNum(s or "0")/3600
end
debuglog = debuglog .. tostring(d)
return d
end
function parseDirection(text)
local direction = mw.ustring.match(text,"%A([NSEWnsew])%A") or mw.ustring.match(text,"^([NSEWnsew])%A") or mw.ustring.match(text,"%A([NSEWnsew])$")
if (not direction) then
direction = mw.ustring.match(text,"([Nn])[Oo][Rr][Tt][Hh]") or mw.ustring.match(text,"([Ss])[Oo][Uu][Tt][Hh]") or mw.ustring.match(text,"([Ee])[Aa][Ss][Tt]") or mw.ustring.match(text,"([Ww])[Ee][Ss][Tt]")
end
if direction then direction = mw.ustring.upper(direction) end
return direction
end
function parseCoord(text)
local text = mw.ustring.upper(text) -- we're only getting direction letters and numbers here
local coord = {}
local ok
-- maybe it's a Coord call like "{{Coord|37.3|N|259.0|E|globe:Mars_type:mountain}}" - then only search the template
text = mw.ustring.match(text,"{{COORD(.-)}}") or text
-- maybe it's a simple coordinate like 37N,33E?
-- note: currently does NOT hunt for deg, min, sec variations. ASSuMEs that order.
-- In this case, parsing what to do based on three numbers starts to fall apart (what if there are five?)
-- Instead, look for the direction markers first, then split into two bound parsing problems
local first, second = mw.ustring.match(text,"^(.-%A)[NSEW](%A.-)$")
if first and second and mw.ustring.match(first,"%d") then
coord[1] = parseValue(first)
second = mw.ustring.match(second, "^(.-%A)[NSEW]%A.-$") or mw.ustring.match(second, "^(.-%A)[NSEW]$") or second
coord[2] = parseValue(second)
if (coord[1] and coord[2]) then ok = true end
end
if (ok) then
-- at this point the amounts of coord[1] (lat) and coord[2] (lon) are set, but what directions?
local firstdir = parseDirection(text)
local seconddir = firstdir
if firstdir then
frag = text
repeat -- I just keep the first letter of the direction, not the context, so need to run forward to it
frag = mw.ustring.match(frag, firstdir .. "(.*)$")
seconddir = parseDirection(frag)
until seconddir ~= firstdir
end
else
-- last ditch effort: take the first two numbers in the section, WHATEVER they are. Can be signed. No directions!
coord[1], coord[2] = mw.ustring.match(text,"(%-?%d+[%.,]?%d*)[%a%c%s%z!@#$%%^&%*%(%)%=|'{}:;<>~`]+(%-?%d+[%.,]?%d*)")
debuglog = debuglog .. "L" .. tostring(coord[1]) .. "D" .. tostring(coord[2])
if not (coord[1] and coord[2]) then return nil end
coord[1] = tidyNum(coord[1])
coord[2] = tidyNum(coord[2])
debuglog = debuglog .. ">"
end
-- invert signs for west, south positions
if (firstdir == "W" or firstdir == "S") then
coord[1] = -1 * coord[1]
end
if (seconddir == "W" or seconddir == "S") then
coord[2] = -1 * coord[2]
end
-- if first is E/W, put it second
if (firstdir == "W" or firstdir == "E") then
coord[1], coord[2] = coord[2], coord[1]
end
-- default without directions specified: first = latitude, no sign reversal
if (not firstdir) then
firstdir = "N"
end
if (not seconddir) then
seconddir = "E"
end
debuglog = debuglog .. tostring(coord[1]) .. tostring(coord[2])
if mw.ustring.match(seconddir,"[NS]") or mw.ustring.match(firstdir,"[EW]") then
return nil, "two of one direction in coordinate"
end
while coord[2] > 180 do
coord[2] = coord[2] - 360
end
while coord[2] < -180 do
coord[2] = coord[2] + 360
end
-- at this point firstdir and seconddir no longer mean anything - direction is in the + or - and first or second position
return coord, warning
end
function getData(pagetitle, database, pRadius, eRadius)
local pagecontent
if pagetitle then
pagecontent = pagetitle:getContent()
end
if not pagecontent then return database end
pagecontent = mw.ustring.gsub(pagecontent, "^.-{|", "{|") -- remove all before first table
if not pagecontent then return database end
pagecontent = mw.ustring.gsub(pagecontent, "|}.-{|", "") or pagecontent -- remove all between tables
pagecontent = mw.ustring.gsub(pagecontent, "|}.-$", "|}") or pagecontent -- remove all after table
local pagerecord = mw.text.split(pagecontent,"|%-") -- separate all table rows into records
for i = 1, #pagerecord do
recordname = mw.ustring.match(pagerecord[i],"%[%[(.-)%]%]")
recordcoord = parseCoord(pagerecord[i])
if recordname and recordcoord then table.insert(database,{recordname, recordcoord}) end
end
return database
end
function getDatabase(pages, pRadius, eRadius)
local database = {}
local page = mw.text.split(pages,"|")
for i = 1, #page do
local pagename = mw.text.trim(page[i] or "")
local pagetitle = mw.title.new(pagename)
database = getData(pagetitle,database, pRadius, eRadius) -- (so far as I know this is a self assignment, actually)
end
return database
end
function display(dataitem)
local recordname, recordcoord = dataitem[1], dataitem[2]
return '"'..recordname..'", {' .. recordcoord[1] .. ", " .. recordcoord[2] .. "}"
end
function displayDatabase(database)
local outarray = {}
local outprefix = "<nowiki><pre>\nreturn {{"
local delimiter = "},\n{"
local outsuffix = "}}\n</pre></nowiki>"
for i = 1, #database do
table.insert(outarray,display(database[i]))
end
return (outprefix .. table.concat(outarray, delimiter) .. outsuffix)
end
function p._main(frame, pRadius, eRadius, defaultdata)
-- for now this is not really intended to be called except from other functions here - use planet name to call
-- handle args in this module
-- other parameters are REQUIRED.
local args = getArgs(frame)
data = args.data or defaultdata
database = getDatabase(data, pRadius, eRadius)
return displayDatabase(database) .. debuglog
end
function p.mars(frame)
-- module name defines Mars - now set the radius accordingly
local pRadius = 3376.2 -- km (polar)
local eRadius = 3396.2 -- km (equatorial)
local defaultdata = 'List of mountains on Mars|List of craters on Mars: A-G|List of craters on Mars: H-N|List of craters on Mars: O-Z|List of catenae on Mars'
return p._main(frame, pRadius, eRadius, defaultdata)
end
function p.venus(frame)
local pRadius = 6051.8 -- km
local eRadius = 6051.8 -- km (doh, it doesn't spin much!)
local defaultdata = 'List of craters on Venus|List of montes on Venus|List of coronae on Venus'
return p._main(frame, pRadius, eRadius, defaultdata)
end
function p.moon(frame)
-- NOTE: our articles listing craters on the Moon don't include coordinates!
-- Also there are so many it might run out the clock on the module, we'd have to see
local pRadius = 1735.97 -- km
local eRadius = 1738.14 -- km
local defaultdata = 'List of lunar features' -- (duplicates:) 'List of mountains on the Moon|List of valleys on the Moon|List of maria on the Moon'
return p._main(frame, pRadius, eRadius, defaultdata)
end
function p.mercury(frame)
local pRadius = 2439.7 -- km
local eRadius = 2439.7 -- km
local defaultdata = 'List of geological features on Mercury|List of craters on Mercury'
-- no coord templates in these, watch for bad coordinates
return p._main(frame, pRadius, eRadius, defaultdata)
end
function p.earthCraters(frame)
-- a general list of all Earth features would be beyond a simple Lua module!
local pRadius = 6356.8 -- km
local eRadius = 6378.1 -- km
local defaultdata = 'List of impact craters in Africa|List of impact craters in Antarctica|List of impact craters in Asia|List of impact craters in Australia|List of impact craters in Europe|List of impact craters in North America|List of impact craters in South America'
return p._main(frame, pRadius, eRadius, defaultdata)
end
return p