Module:Coordinates: Difference between revisions
Created page with "--[[ This module is intended to replace the functionality of {{Coord}} and related templates. It provides several methods, including {{#invoke:Coordinates | coord }} : General function formatting and displaying coordinate values. {{#invoke:Coordinates | dec2dms }} : Simple function for converting decimal degree values to DMS format. {{#invoke:Coordinates | dms2dec }} : Simple function for converting DMS format to decimal degree format. {{#invoke:Coordinates | link }..." |
No edit summary |
||
| Line 73: | Line 73: | ||
--[[ | --[[ | ||
Determine the required CSS class to display coordinates | Determine the required CSS class to display coordinates | ||
]] | ]] | ||
local function displayDefault(default, mode) | local function displayDefault(default, mode) | ||
| Line 92: | Line 88: | ||
--[[ | --[[ | ||
specPrinter | specPrinter | ||
]] | ]] | ||
local function specPrinter(args, coordinateSpec) | local function specPrinter(args, coordinateSpec) | ||
local uriComponents = coordinateSpec["param"] | local uriComponents = coordinateSpec["param"] | ||
if uriComponents == "" then | if uriComponents == "" then | ||
return "ERROR param was empty" | return "ERROR param was empty" | ||
end | end | ||
| Line 114: | Line 106: | ||
local geodeclat | local geodeclat | ||
if lat < 0 then | if lat < 0 then | ||
geodeclat = tostring(coordinateSpec["dec-lat"]):sub(2) .. "°S" | geodeclat = tostring(coordinateSpec["dec-lat"]):sub(2) .. "°S" | ||
else | else | ||
| Line 123: | Line 114: | ||
local geodeclong | local geodeclong | ||
if long < 0 then | if long < 0 then | ||
geodeclong = tostring(coordinateSpec["dec-long"]):sub(2) .. "°W" | geodeclong = tostring(coordinateSpec["dec-long"]):sub(2) .. "°W" | ||
else | else | ||
| Line 160: | Line 150: | ||
end | end | ||
--[[ Helper | --[[ Helper functions for dec2dms ]] | ||
local function convert_dec2dms_d(coordinate) | local function convert_dec2dms_d(coordinate) | ||
local d = math_mod._round( coordinate, 0 ) .. "°" | local d = math_mod._round( coordinate, 0 ) .. "°" | ||
| Line 166: | Line 156: | ||
end | end | ||
local function convert_dec2dms_dm(coordinate) | local function convert_dec2dms_dm(coordinate) | ||
coordinate = math_mod._round( coordinate * 60, 0 ); | coordinate = math_mod._round( coordinate * 60, 0 ); | ||
| Line 172: | Line 161: | ||
coordinate = math.floor( (coordinate - m) / 60 ); | coordinate = math.floor( (coordinate - m) / 60 ); | ||
local d = coordinate % 360 .."°" | local d = coordinate % 360 .."°" | ||
return d .. string.format( "%02d′", m ) | return d .. string.format( "%02d′", m ) | ||
end | end | ||
local function convert_dec2dms_dms(coordinate) | local function convert_dec2dms_dms(coordinate) | ||
coordinate = math_mod._round( coordinate * 60 * 60, 0 ); | coordinate = math_mod._round( coordinate * 60 * 60, 0 ); | ||
| Line 184: | Line 171: | ||
coordinate = math.floor( (coordinate - m) / 60 ); | coordinate = math.floor( (coordinate - m) / 60 ); | ||
local d = coordinate % 360 .."°" | local d = coordinate % 360 .."°" | ||
return d .. string.format( "%02d′", m ) .. string.format( "%02d″", s ) | return d .. string.format( "%02d′", m ) .. string.format( "%02d″", s ) | ||
end | end | ||
local function convert_dec2dms(coordinate, firstPostfix, secondPostfix, precision) | local function convert_dec2dms(coordinate, firstPostfix, secondPostfix, precision) | ||
local coord = tonumber(coordinate) | local coord = tonumber(coordinate) | ||
| Line 211: | Line 193: | ||
end | end | ||
local function convert_dms2dec(direction, degrees_str, minutes_str, seconds_str) | local function convert_dms2dec(direction, degrees_str, minutes_str, seconds_str) | ||
local degrees = tonumber(degrees_str) | local degrees = tonumber(degrees_str) | ||
| Line 234: | Line 213: | ||
local decimal = factor * (degrees+(minutes+seconds/60)/60) | local decimal = factor * (degrees+(minutes+seconds/60)/60) | ||
return string.format( "%." .. precision .. "f", decimal ) | return string.format( "%." .. precision .. "f", decimal ) | ||
end | end | ||
local function validate( lat_d, lat_m, lat_s, long_d, long_m, long_s, source, strong ) | local function validate( lat_d, lat_m, lat_s, long_d, long_m, long_s, source, strong ) | ||
local errors = {}; | local errors = {}; | ||
| Line 250: | Line 226: | ||
if strong then | if strong then | ||
if lat_d < 0 then | if lat_d < 0 then table.insert(errors, {source, "latitude degrees < 0 with hemisphere flag"}) end | ||
if long_d < 0 then table.insert(errors, {source, "longitude degrees < 0 with hemisphere flag"}) end | |||
if long_d < 0 then | |||
end | end | ||
if lat_d > 90 | if lat_d > 90 or lat_d < -90 then table.insert(errors, {source, "latitude degrees out of range"}) end | ||
if lat_m >= 60 or lat_m < 0 then table.insert(errors, {source, "latitude minutes out of range"}) end | |||
if long_d >= 360 or long_d <= -360 then table.insert(errors, {source, "longitude degrees out of range"}) end | |||
if lat_m >= 60 | |||
if long_d >= 360 | |||
return errors; | return errors; | ||
end | end | ||
local function parseDec( lat, long, format ) | local function parseDec( lat, long, format ) | ||
local coordinateSpec = {} | local coordinateSpec = {} | ||
| Line 329: | Line 252: | ||
local mode = coordinates.determineMode( lat, long ); | local mode = coordinates.determineMode( lat, long ); | ||
coordinateSpec["dms-lat"] = convert_dec2dms( lat, "N", "S", mode) | coordinateSpec["dms-lat"] = convert_dec2dms( lat, "N", "S", mode) | ||
coordinateSpec["dms-long"] = convert_dec2dms( long, "E", "W", mode) | coordinateSpec["dms-long"] = convert_dec2dms( long, "E", "W", mode) | ||
coordinateSpec.default = format or "dec" | |||
return coordinateSpec, errors | return coordinateSpec, errors | ||
end | end | ||
local function parseDMS( lat_d, lat_m, lat_s, lat_f, long_d, long_m, long_s, long_f, format ) | local function parseDMS( lat_d, lat_m, lat_s, lat_f, long_d, long_m, long_s, long_f, format ) | ||
local coordinateSpec, errors, backward = {}, {} | local coordinateSpec, errors, backward = {}, {} | ||
| Line 353: | Line 265: | ||
long_f = long_f:upper(); | long_f = long_f:upper(); | ||
if lat_f == 'E' or lat_f == 'W' then | if lat_f == 'E' or lat_f == 'W' then | ||
lat_d, long_d, lat_m, long_m, lat_s, long_s, lat_f, long_f, backward = long_d, lat_d, long_m, lat_m, long_s, lat_s, long_f, lat_f, true; | lat_d, long_d, lat_m, long_m, lat_s, long_s, lat_f, long_f, backward = long_d, lat_d, long_m, lat_m, long_s, lat_s, long_f, lat_f, true; | ||
| Line 363: | Line 274: | ||
elseif not tonumber(long_d) then | elseif not tonumber(long_d) then | ||
return nil, {{"parseDMS", "Longitude could not be parsed as a number:" .. long_d }} | return nil, {{"parseDMS", "Longitude could not be parsed as a number:" .. long_d }} | ||
end | end | ||
coordinateSpec["dms-lat"] = lat_d.."°"..optionalArg(lat_m,"′") .. optionalArg(lat_s,"″") .. lat_f | coordinateSpec["dms-lat"] = lat_d.."°"..optionalArg(lat_m,"′") .. optionalArg(lat_s,"″") .. lat_f | ||
coordinateSpec["dms-long"] = long_d.."°"..optionalArg(long_m,"′") .. optionalArg(long_s,"″") .. long_f | coordinateSpec["dms-long"] = long_d.."°"..optionalArg(long_m,"′") .. optionalArg(long_s,"″") .. long_f | ||
coordinateSpec["dec-lat"] = convert_dms2dec(lat_f, lat_d, lat_m, lat_s) | coordinateSpec["dec-lat"] = convert_dms2dec(lat_f, lat_d, lat_m, lat_s) | ||
coordinateSpec["dec-long"] = convert_dms2dec(long_f, long_d, long_m, long_s) | coordinateSpec["dec-long"] = convert_dms2dec(long_f, long_d, long_m, long_s) | ||
coordinateSpec.default = format or "dms" | |||
return coordinateSpec, errors, backward | return coordinateSpec, errors, backward | ||
end | end | ||
local function formatTest(args) | local function formatTest(args) | ||
local result, errors | local result, errors | ||
| Line 402: | Line 291: | ||
local function getParam(args, lim) | local function getParam(args, lim) | ||
local ret = {} | local ret = {} | ||
for i = 1, lim do | for i = 1, lim do ret[i] = args[i] or '' end | ||
return table.concat(ret, '_') | return table.concat(ret, '_') | ||
end | end | ||
if not args[1] then | if not args[1] then | ||
return errorPrinter( {{"formatTest", "Missing latitude"}} ) | return errorPrinter( {{"formatTest", "Missing latitude"}} ) | ||
elseif not tonumber(args[1]) then | elseif not tonumber(args[1]) and not dmsTest(args[1], 'N') then -- Sadece sayı değilse ve DMS formatı değilse hata ver | ||
return errorPrinter( {{"formatTest", "Unable to parse latitude"}} ) | |||
return errorPrinter( {{"formatTest", "Unable to parse latitude | |||
elseif not args[4] and not args[5] and not args[6] then | elseif not args[4] and not args[5] and not args[6] then | ||
result, errors = parseDec(args[1], args[2], args.format) | result, errors = parseDec(args[1], args[2], args.format) | ||
if not result then | if not result then return errorPrinter(errors); end | ||
result.param = table.concat({ | result.param = table.concat({ | ||
math.abs(tonumber(args[1])), | math.abs(tonumber(args[1])), | ||
| Line 430: | Line 309: | ||
args[3] or ''}, '_') | args[3] or ''}, '_') | ||
elseif dmsTest(args[4], args[8]) then | elseif dmsTest(args[4], args[8]) then | ||
result, errors, backward = parseDMS(args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args.format) | |||
result, errors, backward = parseDMS(args[1], args[2], args[3], args[4], | if not result then return errorPrinter(errors) end | ||
if not result then | |||
result.param = getParam(args, 9) | result.param = getParam(args, 9) | ||
elseif dmsTest(args[3], args[6]) then | elseif dmsTest(args[3], args[6]) then | ||
result, errors, backward = parseDMS(args[1], args[2], nil, args[3], args[4], args[5], nil, args[6], args['format']) | |||
result, errors, backward = parseDMS(args[1], args[2], nil, args[3], | if not result then return errorPrinter(errors) end | ||
if not result then | |||
result.param = getParam(args, 7) | result.param = getParam(args, 7) | ||
elseif dmsTest(args[2], args[4]) then | elseif dmsTest(args[2], args[4]) then | ||
result, errors, backward = parseDMS(args[1], nil, nil, args[2], args[3], nil, nil, args[4], args.format) | |||
result, errors, backward = parseDMS(args[1], nil, nil, args[2], | if not result then return errorPrinter(errors) end | ||
if not result then | |||
result.param = getParam(args, 5) | result.param = getParam(args, 5) | ||
else | else | ||
return errorPrinter({{"formatTest", "Unknown argument format"}}) | |||
return errorPrinter({{"formatTest", "Unknown argument format"}}) | |||
end | end | ||
result.name = args.name | result.name = args.name | ||
local ret = specPrinter(args, result) | local ret = specPrinter(args, result) | ||
return ret, backward | return ret, backward | ||
end | end | ||
--[[ | --[[ WIKIDATA CATEGORIES DISABLED TO PREVENT LUA ERROR ]] | ||
]] | |||
local function makeWikidataCategories(qid) | local function makeWikidataCategories(qid) | ||
return '' | |||
end | end | ||
function coordinates.link(frame) return coord_link; end | |||
coordinates.dec2dms = makeInvokeFunc('_dec2dms') | coordinates.dec2dms = makeInvokeFunc('_dec2dms') | ||
function coordinates._dec2dms(args) | function coordinates._dec2dms(args) | ||
return convert_dec2dms(args[1], args[2] or '', args[3] or '', args[4] or '') | |||
end | end | ||
function coordinates.determineMode( value1, value2 ) | function coordinates.determineMode( value1, value2 ) | ||
local precision = math.max( math_mod._precision( value1 ), math_mod._precision( value2 ) ); | local precision = math.max( math_mod._precision( value1 ), math_mod._precision( value2 ) ); | ||
if precision <= 0 then | if precision <= 0 then return 'd' elseif precision <= 2 then return 'dm'; else return 'dms'; end | ||
end | end | ||
coordinates.dms2dec = makeInvokeFunc('_dms2dec') | coordinates.dms2dec = makeInvokeFunc('_dms2dec') | ||
function coordinates._dms2dec(args) | function coordinates._dms2dec(args) | ||
return convert_dms2dec(args[1], args[2], args[3], args[4]) | |||
end | end | ||
coordinates.coord = makeInvokeFunc('_coord') | coordinates.coord = makeInvokeFunc('_coord') | ||
function coordinates._coord(args) | function coordinates._coord(args) | ||
-- Disable automatic wikidata lookup to prevent errors | |||
local contents, backward = formatTest(args) | local contents, backward = formatTest(args) | ||
local Notes = args.notes or '' | local Notes = args.notes or '' | ||
local Display = args.display and args.display:lower() or 'inline' | local Display = (args.display and args.display:lower()) or 'inline' | ||
local function | local function isInline(s) return s:find('inline') ~= nil or s == 'i' or s == 'it' or s == 'ti' end | ||
local function isInTitle(s) return s:find('title') ~= nil or s == 't' or s == 'it' or s == 'ti' end | |||
local text = '' | local text = '' | ||
| Line 650: | Line 366: | ||
end | end | ||
if isInTitle(Display) then | if isInTitle(Display) then | ||
if not isInline(Display) then | if not isInline(Display) then | ||
text = text .. '<span class="geo-inline-hidden noexcerpt">' .. contents .. Notes .. '</span>' | text = text .. '<span class="geo-inline-hidden noexcerpt">' .. contents .. Notes .. '</span>' | ||
end | end | ||
text = text .. displaytitle(contents .. Notes | text = text .. displaytitle(contents .. Notes) | ||
end | end | ||
-- Parser function call | |||
if not args.nosave then | if not args.nosave then | ||
local | local function coord_wrapper(in_args) | ||
return mw.getCurrentFrame():callParserFunction('#coordinates', in_args) or '' | |||
end | end | ||
if | -- Clean args for parser function | ||
local p_args = {} | |||
text = text .. coord_wrapper( | for k, v in pairs(args) do if type(k) == 'number' then p_args[k] = v end end | ||
if isInTitle(Display) then p_args[10] = 'primary' end | |||
text = text .. coord_wrapper(p_args) | |||
end | end | ||
return text | return text | ||
end | end | ||
function coordinates._coord2text(coord,type) | function coordinates._coord2text(coord,type) | ||
if coord | if coord == '' or not type then return nil end | ||
type = mw.text.trim(type) | type = mw.text.trim(type) | ||
if type == 'lat' or type == 'long' then | if type == 'lat' or type == 'long' then | ||
local coordString = mw.ustring.match(coord,'[%.%d]+°[NS] [%.%d]+°[EW]') | local coordString = mw.ustring.match(coord,'[%.%d]+°[NS] [%.%d]+°[EW]') | ||
if not coordString then | if not coordString then return nil end | ||
local result = mw.text.split(coordString, ' ') | local result = mw.text.split(coordString, ' ') | ||
local negative | local negative = (type == 'lat') and 'S' or 'W' | ||
result = (type == 'lat') and result[1] or result[2] | |||
result = mw.text.split(result, '°') | result = mw.text.split(result, '°') | ||
if result[2] == negative then result[1] = '-'..result[1] end | if result[2] == negative then result[1] = '-'..result[1] end | ||
return result[1] | return result[1] | ||
| Line 720: | Line 408: | ||
end | end | ||
function coordinates.coordinsert(frame) | function coordinates.coordinsert(frame) | ||
for i, v in ipairs(frame.args) do | for i, v in ipairs(frame.args) do | ||
if i ~= 1 then | if i ~= 1 then | ||
if not mw.ustring.find(frame.args[1], (mw.ustring.match(frame.args[i], '^(.-:)') or '')) then | if not mw.ustring.find(frame.args[1], (mw.ustring.match(frame.args[i], '^(.-:)') or '')) then | ||
frame.args[1] = mw.ustring.gsub(frame.args[1], '(params=.-)_? ', '%1_'..frame.args[i]..' ') | frame.args[1] = mw.ustring.gsub(frame.args[1], '(params=.-)_? ', '%1_'..frame.args[i]..' ') | ||
end | end | ||
end | end | ||
end | end | ||
return frame.args[1] | return frame.args[1] | ||
end | end | ||
return coordinates | return coordinates | ||