Module:Sandbox/Wnt/FindFeatures/displayDatabase

-- 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 "37.3°N, 259°W" - then only search the template text = mw.ustring.match(text,"") 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 = " \nreturn {{" local delimiter = "},\n{" local outsuffix = "}}\n " 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