Модуль:AstroCoordinates
Для документации этого модуля может быть создана страница Модуль:AstroCoordinates/doc
--[[
This module is a for of Module:Coordinates
It is intended to implement the functionality of {{AstroCoord}} and related
templates. It provides a method {{#Invoke:AstroCoordinates | coord }} -
a general function formatting and displaying astrocoordinate values.
]]
math_mod = require( "Module:Math" );
globalFrame = nil
coordinates = {};
local Display = '';
--[[ Helper function, replacement for {{coord/display/title}} ]]
function displaytitle (s, notes, globalFrame)
return globalFrame:extensionTag{
name = 'indicator',
content = '[[Файл:Jupiter and moon.png|20px|link=Вторая экваториальная система координат|Экваториальные координаты]] ' .. s .. notes,
args = { name = '0-coord' }
};
end
--[[ Helper function, Replacement for {{coord/display/inline}} ]]
function displayinline (s, notes)
return s .. notes
end
--[[
New function, not from Module:Coordinates
]]
function parseTags(line)
local prefix = ''
local postfix = ''
for i = 1, 2 do
local tag = mw.ustring.match(line, "^<span [^<>]*>");
if tag then
prefix = prefix .. tag
line = mw.ustring.sub(line, mw.ustring.len(tag)+1, -1)
end
end
for i = 1, 2 do
local tag = mw.ustring.match(line, "</ ?span>$");
if tag then
postfix = tag .. postfix
line = mw.ustring.sub(line, 1, mw.ustring.len(line)-mw.ustring.len(tag))
end
end
local ref = mw.ustring.match(line, ".'\"`UNIQ.-.*$");
if ref then
postfix = ref .. postfix
line = mw.ustring.sub(line, 1, mw.ustring.len(line)-mw.ustring.len(ref))
end
for i = 1, 2 do
local tag = mw.ustring.match(line, "</span>.*$");
if tag then
postfix = tag .. postfix
line = mw.ustring.sub(line, 1, mw.ustring.len(line)-mw.ustring.len(tag))
end
end
line = mw.ustring.gsub(line, ' ', ' ')
line = mw.ustring.gsub(line, '°', '°')
line = mw.ustring.gsub(line, '′', '′')
line = mw.ustring.gsub(line, '″', '″')
return prefix, mw.text.trim(line), postfix
end
--[[
parseTempl
Transforms decimal format latitude and longitude into the a
structure to be used in displaying coordinates
Returns (table, table)
]]
function parseTempl( ra, dec, format )
local coordinateSpec = {}
local errors = {}
local ra_prefix, ra, ra_postfix = parseTags(ra) -- TODO: $ at the end
local ra_h, ra_m, ra_s = mw.ustring.match(ra, "^(%+?[0-9]+)<sup>ч</sup>%s*([0-9]+)<sup>м</sup>%s*([0-9,%.]+)<sup>с</sup>");
if not ra_h then
ra_h, ra_m = mw.ustring.match(ra, "^(%+?[0-9]+)<sup>ч</sup>%s*([0-9]+)<sup>м</sup>");
if not ra_h then
ra_h = mw.ustring.match(ra, "^(%+?[0-9]+)<sup>ч</sup>");
if not ra_h then
table.insert(errors, {'parseTempl', 'некорректное прямое восхождение: ' .. ra})
end
end
end
local dec_prefix, dec, dec_postfix = parseTags(dec) -- TODO: $ at the end
local dec_h, dec_m, dec_s = mw.ustring.match(dec, "^([+%-−–]?[0-9]+)°%s*([0-9]+)′%s*([0-9,%.]+)″");
if not dec_h then
dec_h, dec_m = mw.ustring.match(dec, "^([+%-−–]?[0-9]+)°%s*([0-9]+)′");
if not dec_h then
dec_h = mw.ustring.match(dec, "^([+%-−–]?[0-9]+)°");
if not dec_h then
table.insert(errors, {'parseTempl', 'некорректное склонение: ' .. dec})
end
end
end
if #errors == 0 then
coordinateSpec, errors = parseHMS(ra_h, ra_m, ra_s, dec_h, dec_m, dec_s, format)
coordinateSpec['ra-prefix'] = ra_prefix
coordinateSpec['ra-postfix'] = ra_postfix
coordinateSpec['dec-prefix'] = dec_prefix
coordinateSpec['dec-postfix'] = dec_postfix
end
return coordinateSpec, errors
end
--[[ Helper function, handle optional args. ]]
function optionalArg(arg, suplement, prefix, shorten)
if arg ~= nil and arg ~= "" then
if mw.ustring.match(arg, '[,%.]') and shorten then
arg = mw.ustring.gsub(arg, ',', '.')
arg = mw.ustring.format( "%.2f", arg)
end
arg = mw.ustring.gsub(arg, '%.', ',')
return prefix .. arg .. suplement
end
return ""
end
--[[
parseHMS
Transforms hours, minutes, seconds format right ascension and declination
into the structure to be used in displaying coordinates
Returns (table, table)
]]
function parseHMS( ra_h, ra_m, ra_s, dec_h, dec_m, dec_s, format )
local coordinateSpec = {}
local errors = {}
dec_h = mw.ustring.gsub(dec_h, '[−–]', '-') -- minus or en dash to hyphen
errors = validateHMS( ra_h, ra_m, ra_s, dec_h, dec_m, dec_s, 'parseHMS' );
if #errors ~= 0 then
return coordinateSpec, errors
end
if ra_s == '0' and dec_s == '0' then
ra_s, dec_s = nil, nil
if ra_m == '0' and dec_m == '0' then
ra_m, dec_m = nil, nil
end
end
coordinateSpec['raw-hms-ra'] = ra_h ..
optionalArg (ra_m, "", '+') ..
optionalArg (ra_s, "", '+')
coordinateSpec["raw-hms-dec"] = dec_h ..
optionalArg (dec_m, "", '+') ..
optionalArg (dec_s, "", '+')
coordinateSpec["hms-ra"] = ra_h .. "<sup>ч</sup>" ..
optionalArg (ra_m, "<sup>м</sup>", ' ') ..
optionalArg (ra_s, "<sup>с</sup>", ' ', true)
coordinateSpec["hms-dec"] = dec_h .. "°" ..
optionalArg (dec_m, "′", ' ') ..
optionalArg (dec_s, "″", ' ', true)
if format ~= "" then
coordinateSpec.default = format
else
coordinateSpec.default = "hms"
end
return coordinateSpec, errors
end
--[[
specPrinter
Output formatter. Takes the structure generated by either parseTempl,
or parseHMS and formats it for inclusion on Wikipedia.
]]
function specPrinter(args)
local coordinateSpec, errors = formatTest(args)
if errors ~= '' then
return errors
end
if next(coordinateSpec) == nil then -- if is empty
return ''
end
local params = coordinateSpec["param"] -- only main params, not extra_params
local extra_params = coordinateSpec["extra_param"]
local inner = ''
local prefix = ''
local postfix = ''
if args.display == 'inline-ra' then
inner = coordinateSpec['hms-ra']
prefix = coordinateSpec['ra-prefix'] or ''
postfix = coordinateSpec['ra-postfix'] or ''
elseif args.display == 'inline-dec' then
inner = coordinateSpec['hms-dec']
prefix = coordinateSpec['dec-prefix'] or ''
postfix = coordinateSpec['dec-postfix'] or ''
else
inner = coordinateSpec['hms-ra'] .. ' ' .. coordinateSpec['hms-dec']
prefix = '' -- TODO for inline mode
postfix = '' -- TODO for inline mode
end
inner = mw.ustring.gsub(inner, '-', '−') -- hyphen to minus
local maplinkArgs = {
['locale'] = 'ru',
['ra'] = coordinateSpec['raw-hms-ra'],
['de'] = coordinateSpec['raw-hms-dec'],
['show_box'] = args.box or '1',
['box_color'] = args.box_color or '',
['box_width'] = args.box_width or args.box_size or '',
['box_height'] = args.box_height or args.box_size or '',
['view'] = args.view or '',
['zoom'] = args.zoom or '6'
}
local uriComponents = {}
for k, v in pairs( maplinkArgs ) do
if v ~= '' then
table.insert(uriComponents, k .. '=' .. v );
end
end
local result = '<span class="coordinates plainlinks nourlexpansion">'
result = result .. globalFrame:preprocess(
prefix .. '[http://www.wikisky.org?' .. table.concat( uriComponents, '&' ) .. ' ' .. inner .. ']' .. postfix
)
result = result .. '</span>'
return errors and result .. errors or result
end
--[[
Formats any error messages generated for display
Returns string
]]
function errorPrinter(errors)
local result = ""
for i,v in ipairs(errors) do
local errorHTML = '<strong class="error">Небесные координаты: ' .. v[2] .. '</strong>'
result = result .. errorHTML .. "<br>"
end
if #errors > 0 and mw.title.getCurrentTitle():inNamespace(0) then
result = result .. '[[Категория:Википедия:Страницы с неправильными астрономическими координатами]]'
end
return result
end
--[[
Check the input arguments for coord to determine the kind of data being provided
and then make the necessary processing.
Returns (table, string)
]]
function formatTest(args)
local result, errors = {}, {};
local param, extra_param = {}, {}
if args.ra and args.ra ~= '' and args.dec and args.dec ~= '' then
-- template {{ra|...}}, {{dec|...}} logic
result, errors = parseTempl( args.ra, args.dec, args['format'] )
param = { args.ra, args.dec, args[3] };
elseif args.ra_h and args.ra_h ~= '' and args.dec_h and args.dec_h ~= '' then
result, errors = parseHMS( args.ra_h, args.ra_m, args.ra_s,
args.dec_h, args.dec_m, args.dec_s, args['format'] )
param = { args.ra_h, args.ra_m, args.ra_s,
args.dec_h, args.dec_m, args.dec_s, args[1] };
if args[2] ~= '' then
table.insert( errors, { 'formatTest', 'неожиданные дополнительные параметры' } );
end
elseif args[1] ~= '' and args[4] ~= '' then
-- hms logic
result, errors = parseHMS( args[1], args[2], args[3],
args[4], args[5], args[6], args['format'] )
param = { args[1], args[2], args[3], args[4], args[5],
args[6], args[7] };
if args[8] ~= '' then
table.insert( errors, { 'formatTest', 'неожиданные дополнительные параметры' } );
end
else
return {}, ''
end
if not result then
return nil, errorPrinter( errors )
end
local last = table.getn (param)
if param[last] == '' then
table.remove(param, last)
end
local extra_params = { 'box', 'box_size', 'box_width', 'box_height', 'box_color', 'view', 'zoom' }
for _, v in ipairs( extra_params ) do
if (args[v] or '') ~= '' then
extra_params.v = args[v];
end
end
result.param = table.concat( param , '_' );
result.extra_param = table.concat( extra_params , '_' );
return result, errorPrinter( errors )
end
--[[
Checks input values to for out of range errors.
Return a table
]]
function validateHMS( ra_h, ra_m, ra_s, dec_h, dec_m, dec_s, source )
local errors = {};
if ra_h == nil or ra_h == '' then
table.insert(errors, {source, "пропущено прямое восхождение"})
end
if not mw.ustring.match(ra_h, '^%+?[0-9]+$') then
table.insert(errors, {source, "некорректные часы прямого восхождения"})
end
if ra_m ~= nil and ra_m ~= '' and not mw.ustring.match(ra_m, '^[0-9]+$') then
table.insert(errors, {source, "некорректные минуты прямого восхождения: " .. ra_m})
end
if ra_s ~= nil and ra_s ~= '' and not mw.ustring.match(ra_m, '^[0-9,\.]+$') then
table.insert(errors, {source, "некорректные секунды прямого восхождения"})
end
if dec_h == nil or dec_h == '' then
table.insert(errors, {source, "пропущено склонение"})
end
if not mw.ustring.match(dec_h, '^[+%-−–]?[0-9]+$') then
table.insert(errors, {source, "некорректные часы склонения"})
end
if dec_m ~= nil and dec_m ~= '' and not mw.ustring.match(dec_m, '^[0-9]+$') then
table.insert(errors, {source, "некорректные минуты склонения"})
end
if dec_s ~= nil and dec_s ~= '' and not mw.ustring.match(dec_m, '^[0-9,\.]+$') then
table.insert(errors, {source, "некорректные секунды склонения"})
end
ra_h = tonumber( ra_h ) or 0;
ra_m = tonumber( ra_m ) or 0;
ra_s = tonumber( ra_s ) or 0;
dec_h = tonumber( dec_h ) or 0;
dec_m = tonumber( dec_m ) or 0;
dec_s = tonumber( dec_s ) or 0;
if ra_h > 24 then
table.insert(errors, {source, "прямое восхождение > 24"})
end
if ra_h < 0 then
table.insert(errors, {source, "прямое восхождение < 0"})
end
if ra_m > 60 then -- TODO: >=
table.insert(errors, {source, "минуты прямого восхождения > 60"})
end
if ra_m < 0 then
table.insert(errors, {source, "минуты прямого восхождения < 0"})
end
if ra_s > 60 then -- TODO: >=
table.insert(errors, {source, "секунды прямого восхождения > 60"})
end
if ra_s < 0 then
table.insert(errors, {source, "секунды прямого восхождения < 0"})
end
if dec_h > 90 then
table.insert(errors, {source, "склонение > 90"})
end
if dec_h < -90 then
table.insert(errors, {source, "склонение < -90"})
end
if dec_m > 60 then -- TODO: >=
table.insert(errors, {source, "минуты склонения > 60"})
end
if dec_m < 0 then
table.insert(errors, {source, "минуты склонения < 0"})
end
if dec_s > 60 then -- TODO: >=
table.insert(errors, {source, "секунды склонения > 60"})
end
if dec_s < 0 then
table.insert(errors, {source, "секунды склонения < 0"})
end
return errors;
end
--[[
coord
Main entry point for Lua function to implement {{AstroCoord}}
]]
function coordinates.coord(frame)
globalFrame = frame
local args = frame.args
if args[1] == nil then
local pFrame = frame:getParent();
args = pFrame.args;
for k,v in pairs( frame.args ) do
args[k] = v;
end
end
for i=1,8 do
if args[i] == nil then
args[i] = ""
else
args[i] = args[i]:match( '^%s*(.-)%s*$' ); --remove whitespace
end
end
args['format'] = args['format'] or '';
Display = string.lower(args.display or "inline")
local contents = specPrinter(args)
local Notes = args.notes or ""
if Display == '' then
Display = 'inline';
end
local text = ''
if contents ~= '' then
if string.find( Display, 'inline' ) ~= nil then
text = displayinline(contents, Notes)
end
if string.find( Display, 'title' ) ~= nil then
text = text .. displaytitle(contents, Notes, frame)
end
end
return text
end
return coordinates