diff options
author | Marius <mariausol@gmail.com> | 2011-11-25 12:20:14 +0200 |
---|---|---|
committer | Marius <mariausol@gmail.com> | 2011-11-25 12:20:14 +0200 |
commit | 8a9434e331825735e636700d6a509cf770d5ec41 (patch) | |
tree | 6ebe026b4865fa3d197c121d9f1d5d135016c52a /tex/context/base/phys-dim.lua | |
parent | b0b3f63745dbcd338e4ce549c2f8c4427998ffcf (diff) | |
download | context-8a9434e331825735e636700d6a509cf770d5ec41.tar.gz |
beta 2011.11.25 10:34
Diffstat (limited to 'tex/context/base/phys-dim.lua')
-rw-r--r-- | tex/context/base/phys-dim.lua | 415 |
1 files changed, 267 insertions, 148 deletions
diff --git a/tex/context/base/phys-dim.lua b/tex/context/base/phys-dim.lua index 0a271852d..9d1176b78 100644 --- a/tex/context/base/phys-dim.lua +++ b/tex/context/base/phys-dim.lua @@ -12,14 +12,18 @@ if not modules then modules = { } end modules ['phys-dim'] = { -- -- todo: maybe also an sciunit command that converts to si units (1 inch -> 0.0254 m) -- etc .. typical something to do when listening to a news whow or b-movie +-- +-- todo: collect used units for logging (and list of units, but then we need +-- associations too). local V, P, S, R, C, Cc, Cs, matchlpeg, Carg = lpeg.V, lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.match, lpeg.Carg local format, lower = string.format, string.lower local appendlpeg = lpeg.append local mergetable, mergedtable, keys, loweredkeys = table.merge, table.merged, table.keys, table.loweredkeys +local setmetatablenewindex = table.setmetatablenewindex physics = physics or { } -physics.patterns = physics.patterns or { } +physics.units = physics.units or { } local variables = interfaces.variables local v_reverse = variables.reverse @@ -111,7 +115,7 @@ function commands.digits(str,p_c) end end --- units parser +-- tables: local long_prefixes = { Yocto = [[y]], -- 10^{-24} @@ -151,72 +155,76 @@ local long_prefixes = { Zebi = [[Zi]], -- binary Yobi = [[Yi]], -- binary - Degrees = [[°]], - Degree = [[°]], - Deg = [[°]], - ["°"] = [[°]], + Micro = [[µ]], -- 0x00B5 \textmu + Root = [[√]], -- 0x221A } local long_units = { - Meter = [[m]], - Hertz = [[hz]], - Second = [[s]], - Hour = [[h]], - Liter = [[l]], --- Litre = [[l]], - Gram = [[g]], - Newton = [[N]], - Pascal = [[Pa]], - Atom = [[u]], - Joule = [[J]], - Watt = [[W]], - Celsius = [[C]], -- no SI - Kelvin = [[K]], - Fahrenheit = [[F]], -- no SI - Mol = [[mol]], - Mole = [[mol]], - Equivalent = [[eql]], - Farad = [[F]], - Ohm = [[\Omega]], - Siemens = [[S]], - Ampere = [[A]], - Coulomb = [[C]], - Volt = [[V]], - eVolt = [[eV]], - Tesla = [[T]], - VoltAC = [[V\unitsbackspace\unitslower{ac}]], - VoltDC = [[V\unitsbackspace\unitslower{dc}]], - AC = [[V\unitsbackspace\unitslower{ac}]], - DC = [[V\unitsbackspace\unitslower{dc}]], - Bit = [[bit]], - Baud = [[Bd]], - Byte = [[B]], - Erlang = [[E]], - Bequerel = [[Bq]], - Sievert = [[Sv]], - Candela = [[cd]], - Bell = [[B]], - At = [[at]], - Atm = [[atm]], - Bar = [[bar]], - Foot = [[ft]], - Inch = [[inch]], - Cal = [[cal]], - Force = [[f]], - Lux = [[lux]], - Gray = [[Gr]], - Weber = [[Wb]], - Henry = [[H]], - Sterant = [[sr]], - Angstrom = [[Å]], - Gauss = [[G]], - Rad = [[rad]], - RPS = [[RPS]], - RPM = [[RPM]], - RevPerSec = [[RPS]], - RevPerMin = [[RPM]], - Percent = [[\percent]], - Promille = [[\promille]], + Meter = [[m]], + Hertz = [[Hz]], + Second = [[s]], + Hour = [[h]], + Liter = [[l]], +-- Litre = [[l]], + Gram = [[g]], + Newton = [[N]], + Pascal = [[Pa]], + Atom = [[u]], + Bell = [[B]], + Katal = [[kat]], + Dalton = [[Da]], + Joule = [[J]], + Watt = [[W]], + Celsius = [[C]], -- no SI + Kelvin = [[K]], + Fahrenheit = [[F]], -- no SI + Mol = [[mol]], + Mole = [[mol]], + Equivalent = [[eql]], + Farad = [[F]], + Ohm = [[\Omega]], + Siemens = [[S]], + Ampere = [[A]], + Coulomb = [[C]], + Volt = [[V]], + eVolt = [[eV]], + eV = [[eV]], + Tesla = [[T]], + VoltAC = [[V\unitsbackspace\unitslower{ac}]], + VoltDC = [[V\unitsbackspace\unitslower{dc}]], + AC = [[V\unitsbackspace\unitslower{ac}]], + DC = [[V\unitsbackspace\unitslower{dc}]], + Bit = [[bit]], + Baud = [[Bd]], + Byte = [[B]], + Erlang = [[E]], + Bequerel = [[Bq]], + Sievert = [[Sv]], + Candela = [[cd]], + Bel = [[B]], + At = [[at]], + Atm = [[atm]], + Bar = [[bar]], + Foot = [[ft]], + Inch = [[inch]], + Cal = [[cal]], + Force = [[f]], + Lux = [[lx]], + Gray = [[Gr]], + Weber = [[Wb]], + Henry = [[H]], + Sterant = [[sr]], + Tonne = [[t]], + Angstrom = [[Å]], + Gauss = [[G]], + Rad = [[rad]], + RPS = [[RPS]], + RPM = [[RPM]], + RevPerSec = [[RPS]], + RevPerMin = [[RPM]], + Ohm = [[Ω]], -- 0x2126 \textohm + ["Metric Ton"] = [[t]], + ["Electron Volt"] = [[eV]], } local long_operators = { @@ -236,15 +244,6 @@ local long_suffixes = { ICubic = [[-3]], } -long_prefixes.Micro = [[\textmu]] -long_units .Ohm = [[\textohm]] - -mergetable(long_suffixes,loweredkeys(long_suffixes)) - -local long_prefixes_to_long = { } for k, v in next, long_prefixes do long_prefixes_to_long [lower(k)] = k end -local long_units_to_long = { } for k, v in next, long_units do long_units_to_long [lower(k)] = k end -local long_operators_to_long = { } for k, v in next, long_operators do long_operators_to_long[lower(k)] = k end - local short_prefixes_to_long = { y = "Yocto", z = "Zetto", @@ -272,12 +271,17 @@ local short_units_to_long = { -- I'm not sure about casing m = "Meter", Hz = "Hertz", hz = "Hertz", + B = "Bel", + b = "Bel", + lx = "Lux", + -- da = "Dalton", u = "Hour", h = "Hour", s = "Second", g = "Gram", n = "Newton", v = "Volt", + t = "Tonne", l = "Liter", -- w = "Watt", @@ -296,14 +300,6 @@ local short_operators_to_long = { [":"] = "OutOf", } --- local connected = table.tohash { --- "Degrees", --- } - -short_prefixes = { } for k, v in next, short_prefixes_to_long do short_prefixes [k] = long_prefixes [v] end -short_units = { } for k, v in next, short_units_to_long do short_units [k] = long_units [v] end -short_operators = { } for k, v in next, short_operators_to_long do short_operators[k] = long_operators[v] end - local short_suffixes = { -- maybe just raw digit match ["1"] = long_suffixes.Linear, ["2"] = long_suffixes.Square, @@ -327,51 +323,23 @@ local short_suffixes = { -- maybe just raw digit match ["^-3"] = long_suffixes.ICubic, } -local prefixes = long_prefixes -local units = long_units -local operators = long_operators -local suffixes = long_suffixes - -local somespace = P(" ")^0/"" - -local l_prefix = appendlpeg(keys(long_prefixes)) -local l_unit = appendlpeg(keys(long_units)) -local l_operator = appendlpeg(keys(long_operators)) -local l_suffix = appendlpeg(keys(long_suffixes)) - -local l_prefix = appendlpeg(long_prefixes_to_long,l_prefix) -local l_unit = appendlpeg(long_units_to_long,l_unit) -local l_operator = appendlpeg(long_operators_to_long,l_operator) - -local s_prefix = appendlpeg(short_prefixes_to_long) -local s_unit = appendlpeg(short_units_to_long) -local s_operator = appendlpeg(short_operators_to_long) - -local s_suffix = appendlpeg(keys(short_suffixes)) - --- space inside Cs else funny captures and args to function - --- square centi meter per square kilo seconds +local symbol_units = { + Degrees = [[°]], + Degree = [[°]], + Deg = [[°]], + ["°"] = [[°]], + ArcMinute = [[\checkedtextprime]], -- ′ 0x2032 + ArcSecond = [[\checkedtextdoubleprime]], -- ″ 0x2033 + Percent = [[\percent]], + Promille = [[\promille]], + Permille = [[\promille]], +} -local l_suffix = Cs(somespace * l_suffix) -local s_suffix = Cs(somespace * s_suffix) + Cc("") -local l_operator = Cs(somespace * l_operator) - -local combination = P { "start", - l_prefix = Cs(somespace * l_prefix) + Cc(""), - s_prefix = Cs(somespace * s_prefix) + Cc(""), - l_unit = Cs(somespace * l_unit), - s_unit = Cs(somespace * s_unit), - start = V("l_prefix") * V("l_unit") - + V("s_prefix") * V("s_unit") - + V("l_prefix") * V("s_unit") - + V("s_prefix") * V("l_unit"), +local packaged_units = { + Micron = [[\textmu m]], } --- inspect(s_prefix) --- inspect(s_unit) --- square kilo meter --- square km +-- rendering: local unitsPUS = context.unitsPUS local unitsPU = context.unitsPU @@ -400,6 +368,11 @@ l_prefixes .test = { Kilo = "kilo" } l_units .test = { Meter = "meter", Second = "second" } l_operators.test = { Solidus = " per " } +local prefixes = { } +local units = { } +local operators = { } +local suffixes = { } + local function dimpus(p,u,s,wherefrom) if trace_units then report_units("w: [%s], p: [%s], u: [%s], s: [%s]",wherefrom or "?",p or "?",u or "?",s or "?") @@ -411,8 +384,8 @@ local function dimpus(p,u,s,wherefrom) else local lp = l_prefixes[wherefrom] local lu = l_units [wherefrom] - p = lp and lp[p] or p - u = lu and lu[u] or u + p = lp and lp[p] or prefixes[p] or p + u = lu and lu[u] or units [u] or u end s = suffixes[s] or s -- @@ -457,41 +430,187 @@ local function dimop(o,wherefrom) o = operators[o] or o else local lo = l_operators[wherefrom] - o = lo and lo[o] or o + o = lo and lo[o] or operators[o] or o end if o then unitsO(o) end end --- todo 0x -> rm --- pretty large lpeg (maybe do dimension lookup otherwise) --- not ok yet ... we have this p n s problem - -local dimension = ((l_suffix * combination) * Carg(1)) / dimspu - + ((combination * s_suffix) * Carg(1)) / dimpus -local number = lpeg.patterns.number / unitsN -local operator = C((l_operator + s_operator) * Carg(1)) / dimop -- weird, why is the extra C needed here -local whatever = (P(1)^0) / unitsU - -local number = (1-R("az","AZ")-P(" "))^1 / unitsN -- todo: catch { } +local function dimsym(s,wherefrom) -- Do we need to support wherefrom here? + if trace_units then + report_units("w: [%s], s: [%s]",wherefrom,s or "?") + end + s = symbol_units[s] or s + if s then + unitsC(s) + end +end -dimension = somespace * dimension * somespace -number = somespace * number * somespace -operator = somespace * operator * somespace +local function dimpre(p,wherefrom) -- Do we need to support wherefrom here? + if trace_units then + report_units("w: [%s], p: [%s]",wherefrom,p or "?") + end + p = packaged_units[p] or p + if p then + unitsU(p) + end +end -local unitparser = dimension^1 * (operator * dimension^1)^-1 + whatever + P(-1) +-- patterns: +-- +-- space inside Cs else funny captures and args to function +-- +-- square centi meter per square kilo seconds -local p_c_unitdigitparser = (Cc(nil)/unitsNstart) * p_c_dparser * (Cc(nil)/unitsNstop) -- -local c_p_unitdigitparser = (Cc(nil)/unitsNstart) * c_p_dparser * (Cc(nil)/unitsNstop) -- +local function update_parsers() + + local long_prefixes_to_long = { } for k, v in next, long_prefixes do long_prefixes_to_long [lower(k)] = k end + local long_units_to_long = { } for k, v in next, long_units do long_units_to_long [lower(k)] = k end + local long_operators_to_long = { } for k, v in next, long_operators do long_operators_to_long[lower(k)] = k end + local short_prefixes = { } for k, v in next, short_prefixes_to_long do short_prefixes [k] = long_prefixes [v] end + local short_units = { } for k, v in next, short_units_to_long do short_units [k] = long_units [v] end + local short_operators = { } for k, v in next, short_operators_to_long do short_operators [k] = long_operators[v] end + + mergetable(long_suffixes, loweredkeys(long_suffixes)) + mergetable(symbol_units, loweredkeys(symbol_units)) + mergetable(packaged_units,loweredkeys(packaged_units)) + + prefixes = long_prefixes -- used in above functions + units = long_units -- used in above functions + operators = long_operators -- used in above functions + suffixes = long_suffixes -- used in above functions + + local somespace = P(" ")^0/"" + + local l_prefix = appendlpeg(keys(long_prefixes)) + local l_unit = appendlpeg(keys(long_units)) + local l_operator = appendlpeg(keys(long_operators)) + local l_suffix = appendlpeg(keys(long_suffixes)) + + local l_prefix = appendlpeg(long_prefixes_to_long,l_prefix) + local l_unit = appendlpeg(long_units_to_long,l_unit) + local l_operator = appendlpeg(long_operators_to_long,l_operator) + + local s_prefix = appendlpeg(short_prefixes_to_long) + local s_unit = appendlpeg(short_units_to_long) + local s_operator = appendlpeg(short_operators_to_long) + + local s_suffix = appendlpeg(keys(short_suffixes)) + + local c_symbol = appendlpeg(keys(symbol_units)) + local p_unit = appendlpeg(keys(packaged_units)) + + local combination = P { "start", + l_prefix = Cs(somespace * l_prefix) + Cc(""), + s_prefix = Cs(somespace * s_prefix) + Cc(""), + l_unit = Cs(somespace * l_unit), + s_unit = Cs(somespace * s_unit), + start = V("l_prefix") * V("l_unit") -- centi meter + + V("s_prefix") * V("s_unit") -- c m + + V("l_prefix") * V("s_unit") -- centi m + + V("s_prefix") * V("l_unit"), -- c meter + } + + local l_suffix = Cs(somespace * l_suffix) + local s_suffix = Cs(somespace * s_suffix) + Cc("") + local l_operator = Cs(somespace * l_operator) + local p_unit = Cs(somespace * p_unit) + + -- todo 0x -> rm + -- pretty large lpeg (maybe do dimension lookup otherwise) + -- not ok yet ... we have this p n s problem + + local dimension = (p_unit * Carg(1)) / dimpre + + ((l_suffix * combination) * Carg(1)) / dimspu + + ((combination * s_suffix) * Carg(1)) / dimpus + local number = lpeg.patterns.number / unitsN + local operator = ((l_operator + s_operator) * Carg(1)) / dimop -- weird, why is the extra C needed here + local whatever = (P(1)^0) / unitsU + local symbol = c_symbol / dimsym + local packaged = p_unit / dimpre + + local number = (1-R("az","AZ")-P(" "))^1 / unitsN -- todo: catch { } + + symbol = somespace * symbol * somespace + packaged = somespace * packaged * somespace + dimension = somespace * dimension * somespace + number = somespace * number * somespace + operator = somespace * operator * somespace + + dimension = symbol * dimension + dimension + symbol -- too many space tests + + local unitparser = dimension^1 * (operator * dimension^1)^-1 -- dimension^-1 ? + + symbol + + packaged + + whatever + + P(-1) + + local p_c_unitdigitparser = (Cc(nil)/unitsNstart) * p_c_dparser * (Cc(nil)/unitsNstop) -- + local c_p_unitdigitparser = (Cc(nil)/unitsNstart) * c_p_dparser * (Cc(nil)/unitsNstop) -- + + local p_c_combinedparser = dleader * (p_c_unitdigitparser + number)^-1 * unitparser + local c_p_combinedparser = dleader * (c_p_unitdigitparser + number)^-1 * unitparser + + return p_c_combinedparser, c_p_combinedparser +end -local p_c_combinedparser = dleader * (p_c_unitdigitparser + number)^-1 * unitparser -local c_p_combinedparser = dleader * (c_p_unitdigitparser + number)^-1 * unitparser +local p_c_parser = nil +local c_p_parser = nil +local dirty = true function commands.unit(str,wherefrom,p_c) + if dirty then + if trace_units then + report_units("initializing parser") + end + p_c_parser, c_p_parser = update_parsers() + dirty = false + end if p_c == v_reverse then - matchlpeg(p_c_combinedparser,str,1,wherefrom or "") + matchlpeg(p_c_parser,str,1,wherefrom or "") else - matchlpeg(c_p_combinedparser,str,1,wherefrom or "") + matchlpeg(c_p_parser,str,1,wherefrom or "") + end +end + +local function trigger(t,k,v) + rawset(t,k,v) + dirty = true +end + +local t_units = { + prefixes = setmetatablenewindex(long_prefixes,trigger), + units = setmetatablenewindex(long_units,trigger), + operators = setmetatablenewindex(long_operators,trigger), + suffixes = setmetatablenewindex(long_suffixes,trigger), + symbols = setmetatablenewindex(symbol_units,trigger), + packaged = setmetatablenewindex(packaged_units,trigger), +} + +local t_shortcuts = { + prefixes = setmetatablenewindex(short_prefixes_to_long,trigger), + units = setmetatablenewindex(short_units_to_long,trigger), + operators = setmetatablenewindex(short_operators_to_long,trigger), + suffixes = setmetatablenewindex(short_suffixes,trigger), +} + +physics.units.tables = { + units = t_units, + shortcuts = t_shortcuts, +} + +function commands.registerunit(category,list) + if not list or list == "" then + list = category + category = "units" end + local t = t_units[category] + if t then + for k, v in next, utilities.parsers.settings_to_hash(list or "") do + t[k] = v + end + end + inspect(tables) end + |