Module:Sandbox/AlexNB/nmColor

This is the current revision of this page, as edited by imported>AlexNB at 00:15, 28 September 2014. The present address (URL) is a permanent link to this version.

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
local p = {}

local redvalue = 0
local greenvalue = 0
local bluevalue = 0
 
local function nm2RGB(wavelength, IFcorrect)
-- code based on an algorithm from Dan Bruton's Color Science Page: http://www.physics.sfasu.edu/astro/color/spectra.html
-- calculating RGB color components
    if (wavelength >= 380) and (wavelength < 440) then
        redvalue = (440 - wavelength) / 90
        greenvalue = 0
        bluevalue = 1
    elseif (wavelength >= 440) and (wavelength < 490) then
        redvalue = 0
        greenvalue = (wavelength - 440) / 50
        bluevalue = 1
    elseif (wavelength >= 490) and (wavelength < 510) then
        redvalue = 0
        greenvalue = 1
        bluevalue = (510 - wavelength) / 20
    elseif (wavelength >= 510) and (wavelength < 580) then
        redvalue = (wavelength - 510) / 70
        greenvalue = 1
        bluevalue = 0
    elseif (wavelength >= 580) and (wavelength < 645) then
        redvalue = 1
        greenvalue = (645 - wavelength) / 65
        bluevalue = 0
    elseif (wavelength >= 645) and (wavelength <= 780) then
        redvalue = 1
        greenvalue = 0
        bluevalue = 0
    end
-- calculating intensity correction factor
    if IFcorrect then
    local intensityfactor = 0
    if (wavelength >= 380) and (wavelength < 420) then
        intensityfactor = 0.3 + 0.7*(wavelength - 350) / 70
    elseif (wavelength >= 420) and (wavelength <= 700) then
        intensityfactor = 1
    elseif (wavelength > 700) and (wavelength <= 780) then
        intensityfactor = 0.3 + 0.7*(780 - wavelength) / 80
    end
    redvalue = redvalue * intensityfactor
    greenvalue = greenvalue * intensityfactor
    bluevalue = bluevalue * intensityfactor
    end
end

function p.emission(frame)
-- this function returns the string "#RRGGBB" with approximate RGB value for a wavelength passed as a first argument
    local wavelength = tonumber(frame.args[1])
    nm2RGB(wavelength, true)
    local result='#' .. string.format("%.2X%.2X%.2X", 255*redvalue, 255*greenvalue, 255*bluevalue) 
    return result
end

local function absorption_to_visible(wavelength_abs)
-- code based on a color wheel drawn at: http://www2.chemistry.msu.edu/faculty/reusch/virttxtjml/spectrpy/uv-vis/spectrum.htm
   local wavelength_vis
   local minVioletIndigo = 380 -- originally, it was 400
   local maxVioletIndigo = 430
   local widthVioletIndigo = maxVioletIndigo - minVioletIndigo
   local minBlue = 430
   local maxBlue = 490
   local widthBlue = maxBlue - minBlue
   local minGreen = 490
   local maxGreen = 560
   local widthGreen = maxGreen - minGreen
   local minYellow = 560
   local maxYellow = 580
   local widthYellow = maxYellow - minYellow
   local minOrange = 580
   local maxOrange = 650 -- originally, it was 620
   local widthOrange = maxOrange - minOrange
   local minRed = 650 -- originally, it was 620
   local maxRed = 780 -- originally, it was 800
   local widthRed = maxRed - minRed
   if (wavelength_abs>=minVioletIndigo) and (wavelength_abs<=maxVioletIndigo) then
      wavelength_vis = (wavelength_abs - minVioletIndigo)*widthYellow/widthVioletIndigo + minYellow
   elseif (wavelength_abs>minBlue) and (wavelength_abs<=maxBlue) then
      wavelength_vis = (wavelength_abs - minBlue)*widthOrange/widthBlue + minOrange
   elseif (wavelength_abs>minGreen) and (wavelength_abs<=maxGreen) then
      wavelength_vis = (wavelength_abs - minGreen)*widthRed/widthGreen + minRed
   elseif (wavelength_abs>minYellow) and (wavelength_abs<=maxYellow) then
      wavelength_vis = (wavelength_abs - minYellow)*widthVioletIndigo/widthYellow + minVioletIndigo
   elseif (wavelength_abs>minOrange) and (wavelength_abs<=maxOrange) then
      wavelength_vis = (wavelength_abs - minOrange)*widthBlue/widthOrange + minBlue
   elseif (wavelength_abs>minRed) and (wavelength_abs<=maxRed) then
      wavelength_vis = (wavelength_abs - minRed)*widthGreen/(widthRed + 20) + minGreen
-- one of the "corrected" versions: wavelength_vis = (wavelength_abs - minRed - 30)*widthGreen/widthRed + minGreen
   end
   return wavelength_vis
end

local minAntiMagenta = 550
local maxAntiMagenta = 570

local function process_magenta(wavelength_abs)
   local redvalue_RED
   local bluevalue_RED
   local greenvalue_RED
   local redvalue_BLUE
   local bluevalue_BLUE
   local greenvalue_BLUE
   local widthAntiMagenta = maxAntiMagenta - minAntiMagenta
   local bias_BLUE = (wavelength_abs - minAntiMagenta)/widthAntiMagenta
   local bias_RED = (maxAntiMagenta - wavelength_abs)/widthAntiMagenta
   nm2RGB(700, false)
   redvalue_RED = redvalue*bias_RED
   bluevalue_RED = bluevalue*bias_RED
   greenvalue_RED = greenvalue*bias_RED
   nm2RGB(400, false)
   redvalue_BLUE = redvalue*bias_BLUE
   bluevalue_BLUE = bluevalue*bias_BLUE
   greenvalue_BLUE = greenvalue*bias_BLUE
   redvalue = 0.6+ 0.4*(redvalue_RED + redvalue_BLUE)
   bluevalue = 0.7 + 0.3*(bluevalue_RED + bluevalue_BLUE)
   greenvalue = greenvalue_RED + greenvalue_BLUE
end

function p.absorption(frame)
-- this function returns the string "#RRGGBB" with approximate RGB value for a complementary color (reflection) to a color, defined as a wavelength passed as a first argument
    local wavelength = tonumber(frame.args[1])
-- adding magentas to smoothen red->blue transition. Trying 540..570 nm
    if (wavelength>=minAntiMagenta) and (wavelength<=maxAntiMagenta) then
       process_magenta(wavelength)
       else nm2RGB(absorption_to_visible(wavelength), false)
    end
    local result='#' .. string.format("%.2X%.2X%.2X", 255*redvalue, 255*greenvalue, 255*bluevalue) 
    return result
end


return p