Jump to content

Module:Weather/sandbox

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Erutuon (talk | contribs) at 02:54, 11 September 2016 (copied from Module:Weather). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
(diff) ← Previous revision | Latest revision (diff) | Newer revision → (diff)

-- Efficient (fast) functions to implement cells in tables of weather data.
-- Temperature conversion is built-in, but for simplicity, temperatures
-- are assumed to be for habitable locations (from -100 to 100 °C).

local MINUS = '−'  -- Unicode U+2212 MINUS SIGN

local function temperature_style(value)
	-- Return style for a table cell based on the given value which
	-- should be a temperature in °C.
	local function show(bg, fg)
		if not fg and value and (value < -23.3 or value >= 37.8) then
			fg = 'FFFFFF'
		end
		if fg then
			fg = 'color:#' .. fg .. ';'
		else
			fg = ''
		end
		return 'style="background:#' .. bg .. ';' .. fg .. ' font-size:85%;"'
	end
	if type(value) ~= 'number' then
		return show('FFFFFF', '000000')
	end
	local red, green, blue
	if value < -1000 or value > 60 then
		red = 0
	elseif value < 4.47 then
		red = 5.4 * (42.75 + value)
	elseif value > 41.5 then
		red = 13.78 * (60 - value)
	else
		red = 255
	end
	if value < -42.75 or value > 41.5 then
		green = 0
	elseif value < 4.47 then
		green = 5.4 * (42.75 + value)
	elseif value > 4.5 then
		green = 6.89 * (41.5 - value)
	else
		green = 255
	end
	if value < -90 or value > 23 then
		blue = 0
	elseif value < -42.78 then
		blue = 5.4 * (90 + value)
	elseif value > 4.5 then
		blue = 13.78 * (23 - value)
	else
		blue = 255
	end
	return show(string.format('%02X%02X%02X', red, green, blue))
end

local function format_cell(value, intext, outtext)
	-- Return one line of wikitext to make a cell in a table.
	if not value then
		return '|\n'
	end
	local text
	if outtext then
		text = intext .. '<br>(' .. outtext .. ')'
	else
		text = intext
	end
	return '| ' .. temperature_style(value) .. ' | ' .. text .. '\n'
end

local function process_temperature(intext, inunit, swap)
	-- Convert °C to °F or vice versa, assuming the temperature is for a
	-- habitable location, well inside the range -100 to 100 °C.
	-- That simplifies determining precision and formatting (no commas are needed).
	-- Return (celsius_value, intext, outtext) if valid; otherwise return nil.
	-- The returned input and output are swapped if requested.
	-- Each returned string has a Unicode MINUS as sign, if negative.
	local invalue = tonumber(intext)
	if not invalue then return nil end
	local integer, dot, decimals = intext:match('^%s*%-?(%d+)(%.?)(%d*)%s*$')
	if not integer then return nil end
	if invalue < 0 then
		intext = MINUS .. integer .. dot .. decimals
	end
	local outtext
	if inunit == 'C' or inunit == 'F' then
		local celsius_value, outvalue
		if inunit == 'C' then
			outvalue = invalue * (9/5) + 32
			celsius_value = invalue
		else
			outvalue = (invalue - 32) * (5/9)
			celsius_value = outvalue
		end
		local precision = dot == '' and 0 or #decimals
		outtext = string.format('%.' .. precision .. 'f', math.abs(outvalue) + 2e-14)
		if outvalue < 0 and tonumber(outtext) ~= 0 then
			-- Don't show minus if result is negative but rounds to zero.
			outtext = MINUS .. outtext
		end
		if swap then
			return celsius_value, outtext, intext
		end
		return celsius_value, intext, outtext
	end
	-- LATER Think about whether a no-conversion option would be useful.
	return invalue, intext, outtext
end

local function temperature_row(row, inunit, swap)
	-- Return 13 lines specifying the style/content of 13 table cells.
	-- Input is 13 space-separated words, each a number (°C or °F).
	-- Any word that is not a number gives a blank cell ("M" for a missing cell).
	-- Any excess words are ignored.
	--
	-- Function  Input   Output
	-- ------------------------
	-- CtoF        C       C/F
	-- FfromC      C       F/C
	-- CfromF      F       C/F
	-- FtoC        F       F/C
	local nrcol = 13
	local results, n = {}, 0
	for word in row:gmatch('%S+') do
		n = n + 1
		if n > nrcol then
			break
		end
		results[n] = format_cell(process_temperature(word, inunit, swap))
	end
	for i = n + 1, nrcol do
		results[i] = format_cell()
	end
	return table.concat(results)
end

local function CtoF(frame)
	return temperature_row(frame.args[1], 'C')
end

local function CfromF(frame)
	return temperature_row(frame.args[1], 'F', true)
end

local function FtoC(frame)
	return temperature_row(frame.args[1], 'F')
end

local function FfromC(frame)
	return temperature_row(frame.args[1], 'C', true)
end

return {
	CtoF = CtoF,
	CfromF = CfromF,
	FtoC = FtoC,
	FfromC = FfromC,
}