diff options
author | Karl Berry <karl@freefriends.org> | 2013-04-08 00:43:40 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2013-04-08 00:43:40 +0000 |
commit | 824f7b0903de8ad7f6ee3d7656005e4c59155e06 (patch) | |
tree | abfc8673ef9916f3ab7074e811207384c301492b /Master/texmf-dist/tex/context/base/chem-str.lua | |
parent | 689aefb0727676ed3cddf331337b4be226495e72 (diff) |
context import for TL13, from www.pragma-ade.com/context/beta/cont-tmf.zip
git-svn-id: svn://tug.org/texlive/trunk@29731 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/context/base/chem-str.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/chem-str.lua | 957 |
1 files changed, 625 insertions, 332 deletions
diff --git a/Master/texmf-dist/tex/context/base/chem-str.lua b/Master/texmf-dist/tex/context/base/chem-str.lua index fb325ccea9f..311b70b2d1b 100644 --- a/Master/texmf-dist/tex/context/base/chem-str.lua +++ b/Master/texmf-dist/tex/context/base/chem-str.lua @@ -1,168 +1,263 @@ if not modules then modules = { } end modules ['chem-str'] = { version = 1.001, comment = "companion to chem-str.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + author = "Hans Hagen and Alan Braslau", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } --- This module in incomplete and experimental. - --- We can push snippets into an mp instance. - -local trace_structure = false trackers.register("chemistry.structure", function(v) trace_structure = v end) -local trace_textstack = false trackers.register("chemistry.textstack", function(v) trace_textstack = v end) +-- The original \PPCHTEX\ code was written in pure \TEX\, although later we made +-- the move from \PICTEX\ to \METAPOST\. The current implementation is a mix between +-- \TEX\, \LUA\ and \METAPOST. Although the first objective is to get a compatible +-- but better implementation, later versions might provide more. +-- +-- Well, the later version has arrived as Alan took it upon him to make the code +-- deviate even further from the original implementation. The original (early \MKII) +-- variant operated within the boundaries of \PICTEX\ and as it supported MetaPost as +-- alternative output. As a consequence it still used a stepwise graphic construction +-- approach. As we used \TEX\ for parsing, the syntax was more rigid than it is now. +-- This new variant uses a more mathematical and metapostisch approach. In the process +-- more rendering variants have been added and alignment has been automated. As a result +-- the current user interface is slightly different from the old one but hopefully users +-- will like the added value. + +-- directive_strictorder: one might set this to off when associated texts are disordered too + +local trace_structure = false trackers .register("chemistry.structure", function(v) trace_structure = v end) +local trace_metapost = false trackers .register("chemistry.metapost", function(v) trace_metapost = v end) +local trace_boundingbox = false trackers .register("chemistry.boundingbox", function(v) trace_boundingbox = v end) +local trace_textstack = false trackers .register("chemistry.textstack", function(v) trace_textstack = v end) +local directive_strictorder = true directives.register("chemistry.strictorder", function(v) directive_strictorder = v end) +local directive_strictindex = false directives.register("chemistry.strictindex", function(v) directive_strictindex = v end) local report_chemistry = logs.reporter("chemistry") local format, gmatch, match, lower, gsub = string.format, string.gmatch, string.match, string.lower, string.gsub -local concat, insert, remove = table.concat, table.insert, table.remove -local processor_tostring = typesetters.processors.tostring -local lpegmatch = lpeg.match +local concat, insert, remove, unique, sorted = table.concat, table.insert, table.remove, table.unique, table.sorted +local processor_tostring = typesetters and typesetters.processors.tostring local settings_to_array = utilities.parsers.settings_to_array +local settings_to_array_with_repeat = utilities.parsers.settings_to_array_with_repeat +local formatters = string.formatters -local P, R, S, C, Cs, Ct, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.Cc +local lpegmatch = lpeg.match +local P, R, S, C, Cs, Ct, Cc, Cmt = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.Cc, lpeg.Cmt -local variables = interfaces.variables -local context = context +local variables = interfaces and interfaces.variables +local context = context +local formatters = string.formatters -chemicals = chemicals or { } -local chemicals = chemicals +local v_default = variables.default +local v_small = variables.small +local v_medium = variables.medium +local v_big = variables.big +local v_normal = variables.normal +local v_fit = variables.fit +local v_on = variables.on +local v_none = variables.none -chemicals.instance = "metafun" -- "ppchtex" -chemicals.format = "metafun" -chemicals.structures = 0 +local mpnamedcolor = attributes.colors.mpnamedcolor +local topoints = number.topoints +local todimen = string.todimen -local remapper = { - ["+"] = "p", - ["-"] = "m", -} +chemistry = chemistry or { } +local chemistry = chemistry + +chemistry.instance = "chemistry" +chemistry.format = "metafun" +chemistry.structures = 0 local common_keys = { - b = "line", eb = "line", db = "line", er = "line", dr = "line", br = "line", - sb = "line", msb = "line", psb = "line", - r = "line", pr = "line", mr = "line", - au = "line", ad = "line", - rb = "line", mrb = "line", prb = "line", - rd = "line", mrd = "line", prd = "line", - sr = "line", msr = "line", psr = "line", - c = "line", cc = "line", cd = "line", ccd = "line", - rn = "number", rtn = "number", rbn = "number", - s = "line", ss = "line", pss = "line", mss = "line", - mid = "fixed", mids = "fixed", midz = "text", - z = "text", rz = "text", mrz = "text", prz = "text", crz = "text", - rt = "text", rtt = "text", rbt = "text", zt = "text", zn = "number", - mov = "transform", rot = "transform", adj = "transform", dir = "transform", sub = "transform", + b = "line", + r = "line", + sb = "line", + sr = "line", + rd = "line", + rh = "line", + rb = "line", + rbd = "line", + cc = "line", + ccd = "line", + line = "line", + dash = "line", + arrow = "line", + c = "fixed", + cd = "fixed", + z = "text", + zt = "text", + zlt = "text", + zrt = "text", + rz = "text", + rt = "text", + lrt = "text", + rrt = "text", + label = "text", + zln = "number", + zrn = "number", + rn = "number", + lrn = "number", + rrn = "number", + zn = "number", + number = "number", + mov = "transform", + mark = "transform", + move = "transform", + diff = "transform", + off = "transform", + adj = "transform", + sub = "transform", } local front_keys = { - b = "line", bb= "line", - sb = "line", msb = "line", psb = "line", - r = "line", pr = "line", mr = "line", - z = "text", mrz = "text", prz = "text", + bb = "line", + eb = "line", + rr = "line", + lr = "line", + lsr = "line", + rsr = "line", + lrd = "line", + rrd = "line", + lrh = "line", + rrh = "line", + lrbd = "line", + rrbd = "line", + lrb = "line", + rrb = "line", + lrz = "text", + rrz = "text", + lsub = "transform", + rsub = "transform", } local one_keys = { - sb = "line", db = "line", tb = "line", - ep = "line", es = "line", ed = "line", et = "line", - sd = "line", ldd = "line", rdd = "line", - hb = "line", bb = "line", oe = "line", bd = "line", bw = "line", - z = "text", cz = "text", zt = "text", zn = "number", - zbt = "text", zbn = "number", ztt = "text", ztn = "number", - mov = "transform", sub = "transform", dir = "transform", off = "transform", + db = "line", + tb = "line", + bb = "line", + dr = "line", + hb = "line", + bd = "line", + bw = "line", + oe = "line", + sd = "line", + rdb = "line", + ldb = "line", + ldd = "line", + rdd = "line", + ep = "line", + es = "line", + ed = "line", + et = "line", + cz = "text", + rot = "transform", + dir = "transform", + rm = "transform", + mir = "transform", } -local front_align = { - mrz = { { "b","b","b","b","b","b" } }, - prz = { { "t","t","t","t","t","t" } }, +local ring_keys = { + db = "line", + br = "line", + lr = "line", + rr = "line", + lsr = "line", + rsr = "line", + lrd = "line", + rrd = "line", + lrb = "line", + rrb = "line", + lrh = "line", + rrh = "line", + lrbd = "line", + rrbd = "line", + dr = "line", + eb = "line", + er = "line", + ed = "line", + au = "line", + ad = "line", + s = "line", + ss = "line", + mid = "line", + mids = "line", + midz = "text", + lrz = "text", + rrz = "text", + crz = "text", + rot = "transform", + mir = "transform", + adj = "transform", + lsub = "transform", + rsub = "transform", + rm = "transform", } +-- table.setmetatableindex(front_keys,common_keys) +-- table.setmetatableindex(one_keys,common_keys) +-- table.setmetatableindex(ring_keys,common_keys) + +-- or (faster but not needed here): + +front_keys = table.merged(front_keys,common_keys) +one_keys = table.merged(one_keys,common_keys) +ring_keys = table.merged(ring_keys,common_keys) + local syntax = { - one = { - n = 1, max = 8, keys = one_keys, - align = { - z = { { "r", "r_b", "b", "l_b", "l", "l_t", "t", "r_t" } }, ---~ z = { { "r", "r", "b", "l", "l", "l", "t", "r" } }, - } - }, - three = { - n = 3, max = 3, keys = common_keys, - align = { - mrz = { { "r","b","l" }, { "b","l","t" }, { "l","t","r" }, { "t","r","b" } }, - rz = { { "r","l_b","l_t" }, { "b","l_t","r_t" }, { "l","r_t","r_b" }, { "t","r_b","l_b" } }, - prz = { { "r","l","t" }, { "b","t","r" }, { "l","r","b" }, { "t","b","l" } }, - } - }, - four = { - n = 4, max = 4, keys = common_keys, - align = { - mrz = { { "t","r","b","l" }, { "r","b","l","t" }, { "b","l","t","r" }, { "l","t","r","b" } }, - rz = { { "r_t","r_b","l_b","l_t" }, { "r_b","l_b","l_t","r_t" }, { "l_b","l_t","r_t","r_b" }, { "l_t","r_t","r_b","l_b" } }, - prz = { { "r","b","l","t" }, { "b","l","t","r" }, { "l","t","r","b" }, { "t","r","b","l" } }, - } - }, - five = { - n = 5, max = 5, keys = common_keys, - align = { - mrz = { { "t","r","b","b","l" }, { "r","b","l","l","t" }, { "b","l","t","r","r" }, { "l","t","r","r","b" } }, - rz = { { "r","r","b","l","t" }, { "b","b","l","t","r" }, { "l","l","t","r","b" }, { "t","t","r","b","l" } }, - prz = { { "r","b","l","t","t" }, { "b","l","t","r","r" }, { "l","t","r","b","b" }, { "t","r","b","l","l" } }, - } - }, - six = { - n = 6, max = 6, keys = common_keys, - align = { - mrz = { { "t","t","r","b","b","l" }, { "r","b","b","l","t","t" }, { "b","b","l","t","t","r" }, { "l","t","t","r","b","b" } }, - rz = { { "r","r","b","l","l","t" }, { "b","b","l","t","t","r" }, { "l","l","t","r","r","b" }, { "t","t","r","b","b","l" } }, - prz = { { "r","b","l","l","t","r" }, { "b","l","t","t","r","b" }, { "l","t","r","r","b","l" }, { "t","r","b","b","l","t" } }, - } - }, - eight = { - n = 8, max = 8, keys = common_keys, - align = { -- todo - mrz = { { "t","r","r","b","b","l","l","t" }, { "r","b","b","l","l","t","t","r" }, { "b","l","l","t","t","r","r","b" }, { "l","t","t","r","r","b","b","l" } }, - rz = { { "r","r","b","b","l","l","t","t" }, { "b","b","l","l","t","t","r","r" }, { "l","l","t","t","r","r","b","b" }, { "t","t","r","r","b","b","l","l" } }, - prz = { { "r","b","b","l","l","t","t","r" }, { "b","l","l","t","t","r","r","b" }, { "l","t","t","r","r","b","b","l" }, { "t","r","r","b","b","l","l","t" } }, - } - }, - five_front = { - n = -5, max = 5, keys = front_keys, align = front_align, - }, - six_front = { - n = -6, max = 6, keys = front_keys, align = front_align, - }, - pb = { direct = 'chem_pb ;' }, - pe = { direct = 'chem_pe ;' }, - save = { direct = 'chem_save ;' }, - restore = { direct = 'chem_restore ;' }, - space = { direct = 'chem_symbol("\\chemicalsymbol[space]") ;' }, - plus = { direct = 'chem_symbol("\\chemicalsymbol[plus]") ;' }, - minus = { direct = 'chem_symbol("\\chemicalsymbol[minus]") ;' }, - gives = { direct = 'chem_symbol("\\chemicalsymbol[gives]{%s}{%s}") ;', arguments = 2 }, - equilibrium = { direct = 'chem_symbol("\\chemicalsymbol[equilibrium]{%s}{%s}") ;', arguments = 2 }, - mesomeric = { direct = 'chem_symbol("\\chemicalsymbol[mesomeric]{%s}{%s}") ;', arguments = 2 }, - opencomplex = { direct = 'chem_symbol("\\chemicalsymbol[opencomplex]") ;' }, - closecomplex = { direct = 'chem_symbol("\\chemicalsymbol[closecomplex]") ;' }, + carbon = { max = 4, keys = one_keys, }, + alkyl = { max = 4, keys = one_keys, }, + newmanstagger = { max = 6, keys = one_keys, }, + newmaneclipsed = { max = 6, keys = one_keys, }, + one = { max = 8, keys = one_keys, }, + three = { max = 3, keys = ring_keys, }, + four = { max = 4, keys = ring_keys, }, + five = { max = 5, keys = ring_keys, }, + six = { max = 6, keys = ring_keys, }, + seven = { max = 7, keys = ring_keys, }, + eight = { max = 8, keys = ring_keys, }, + nine = { max = 9, keys = ring_keys, }, + fivefront = { max = 5, keys = front_keys, }, + sixfront = { max = 6, keys = front_keys, }, + chair = { max = 6, keys = front_keys, }, + boat = { max = 6, keys = front_keys, }, + pb = { direct = 'chem_pb;' }, + pe = { direct = 'chem_pe;' }, + save = { direct = 'chem_save;' }, + restore = { direct = 'chem_restore;' }, + chem = { direct = formatters['chem_symbol("\\chemicaltext{%s}");'], arguments = 1 }, + space = { direct = 'chem_symbol("\\chemicalsymbol[space]");' }, + plus = { direct = 'chem_symbol("\\chemicalsymbol[plus]");' }, + minus = { direct = 'chem_symbol("\\chemicalsymbol[minus]");' }, + gives = { direct = formatters['chem_symbol("\\chemicalsymbol[gives]{%s}{%s}");'], arguments = 2 }, + equilibrium = { direct = formatters['chem_symbol("\\chemicalsymbol[equilibrium]{%s}{%s}");'], arguments = 2 }, + mesomeric = { direct = formatters['chem_symbol("\\chemicalsymbol[mesomeric]{%s}{%s}");'], arguments = 2 }, + opencomplex = { direct = 'chem_symbol("\\chemicalsymbol[opencomplex]");' }, + closecomplex = { direct = 'chem_symbol("\\chemicalsymbol[closecomplex]");' }, + reset = { direct = 'chem_reset;' }, + mp = { direct = formatters['%s'], arguments = 1 }, -- backdoor MP code - dangerous! } -local definitions = { } +chemistry.definitions = chemistry.definitions or { } +local definitions = chemistry.definitions + +storage.register("chemistry/definitions",definitions,"chemistry.definitions") -function chemicals.undefine(name) +function chemistry.undefine(name) definitions[lower(name)] = nil end -function chemicals.define(name,spec,text) +function chemistry.define(name,spec,text) name = lower(name) local dn = definitions[name] - if not dn then dn = { } definitions[name] = dn end + if not dn then + dn = { } + definitions[name] = dn + end dn[#dn+1] = { - spec = settings_to_array(lower(spec)), - text = settings_to_array(text), + spec = settings_to_array_with_repeat(spec,true), + text = settings_to_array_with_repeat(text,true), } end -local metacode, variant, keys, bonds, max, txt, textsize, rot, pstack -local molecule = chemicals.molecule -- or use lpegmatch(chemicals.moleculeparser,...) +local metacode, variant, keys, max, txt, pstack, sstack, align +local molecule = chemistry.molecule -- or use lpegmatch(chemistry.moleculeparser,...) local function fetch(txt) local st = stack[txt] @@ -174,305 +269,511 @@ local function fetch(txt) end if t then if trace_textstack then - report_chemistry("fetching from stack %s slot %s: %s",txt,st.n,t) + report_chemistry("fetching from stack %a, slot %a, data %a",txt,st.n,t) end st.n = st.n + 1 end return txt, t end -local digit = R("09")/tonumber +local remapper = { + ["+"] = "p", + ["-"] = "m", +} + +local dchrs = R("09") +local sign = S("+-") +local digit = dchrs / tonumber +local amount = (sign^-1 * (dchrs^0 * P('.'))^-1 * dchrs^1) / tonumber +local single = digit +local range = digit * P("..") * digit +local set = Ct(digit^2) local colon = P(":") local equal = P("=") local other = 1 - digit - colon - equal -local remapped = S("+-") / remapper -local operation = Cs((remapped^0 * other)^1) -local amount = digit -local single = digit +local remapped = sign / remapper +local operation = Cs(other^1) local special = (colon * C(other^1)) + Cc("") -local range = digit * P("..") * digit -local set = Ct(digit^2) local text = (equal * C(P(1)^0)) + Cc(false) local pattern = - (amount + Cc(1)) * - operation * - special * ( + (amount + Cc(1)) + * (remapped + Cc("")) + * Cs(operation/lower) + * Cs(special/lower) * ( range * Cc(false) * text + Cc(false) * Cc(false) * set * text + single * Cc(false) * Cc(false) * text + Cc(false) * Cc(false) * Cc(false) * text ) ---~ local n, operation, index, upto, set, text = lpegmatch(pattern,"RZ1357") - ---~ print(lpegmatch(pattern,"RZ=x")) 1 RZ false false false x ---~ print(lpegmatch(pattern,"RZ1=x")) 1 RZ 1 false false x ---~ print(lpegmatch(pattern,"RZ1..3=x")) 1 RZ 1 3 false x ---~ print(lpegmatch(pattern,"RZ13=x")) 1 RZ false false table x - -local function process(spec,text,n,rulethickness,rulecolor,offset) - insert(stack,{ spec=spec, text=text, n=n }) +-- local n, operation, index, upto, set, text = lpegmatch(pattern,"RZ1357") + +-- print(lpegmatch(pattern,"RZ=x")) -- 1 RZ false false false x +-- print(lpegmatch(pattern,"RZ1=x")) -- 1 RZ 1 false false x +-- print(lpegmatch(pattern,"RZ1..3=x")) -- 1 RZ 1 3 false x +-- print(lpegmatch(pattern,"RZ13=x")) -- 1 RZ false false table x + +local f_initialize = 'if unknown context_chem : input mp-chem.mpiv ; fi ;' +local f_start_structure = formatters['chem_start_structure(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s);'] +local f_set_trace_bounds = formatters['chem_trace_boundingbox := %l ;'] +local f_stop_structure = 'chem_stop_structure;' +local f_start_component = 'chem_start_component;' +local f_stop_component = 'chem_stop_component;' +local f_line = formatters['chem_%s%s(%s,%s,%s,%s,%s);'] +local f_set = formatters['chem_set(%s);'] +local f_number = formatters['chem_%s%s(%s,%s,"\\chemicaltext{%s}");'] +local f_text = f_number +local f_empty_normal = formatters['chem_%s(%s,%s,"");'] +local f_empty_center = formatters['chem_c%s(%s,%s,"");'] +local f_transform = formatters['chem_%s(%s,%s,%s);'] + +local prepareMPvariable = commands and commands.prepareMPvariable + +local function process(level,spec,text,n,rulethickness,rulecolor,offset,default_variant) + insert(stack,{ spec = spec, text = text, n = n }) local txt = #stack local m = #metacode + local saved_rulethickness = rulethickness + local saved_rulecolor = rulecolor + local saved_align = align + local current_variant = default_variant or "six" for i=1,#spec do - local s = spec[i] - local d = definitions[s] + local step = spec[i] + local s = lower(step) + local n = current_variant .. ":" .. s + local d = definitions[n] + if not d then + n = s + d = definitions[n] + end if d then + if trace_structure then + report_chemistry("level %a, step %a, definition %a, snippets %a",level,step,n,#d) + end for i=1,#d do local di = d[i] - process(di.spec,di.text,1,rulethickness,rulecolor) + current_variant = process(level+1,di.spec,di.text,1,rulethickness,rulecolor,offset,current_variant) -- offset? end else - local rep, operation, special, index, upto, set, text = lpegmatch(pattern,s) - if operation == "pb" then + local factor, osign, operation, special, index, upto, set, text = lpegmatch(pattern,step) + if trace_structure then + local set = set and concat(set," ") or "-" + report_chemistry("level %a, step %a, factor %a, osign %a, operation %a, special %a, index %a, upto %a, set %a, text %a", + level,step,factor,osign,operation,special,index,upto,set,text) + end + if operation == "rulecolor" then + local t = text + if not t then + txt, t = fetch(txt) + end + if t == v_default or t == v_normal or t == "" then + rulecolor = saved_rulecolor + elseif t then + rulecolor = mpnamedcolor(t) + end + elseif operation == "rulethickness" then + local t = text + if not t then + txt, t = fetch(txt) + end + if t == v_default or t == v_normal or t == t_medium or t == "" then + rulethickness = saved_rulethickness + elseif t == v_small then + rulethickness = topoints(1/1.2 * todimen(saved_rulethickness)) + elseif t == v_big then + rulethickness = topoints(1.2 * todimen(saved_rulethickness)) + elseif t then + -- rulethickness = topoints(todimen(t)) -- mp can't handle sp + rulethickness = topoints(tonumber(t) * todimen(saved_rulethickness)) + end + elseif operation == "symalign" then + local t = text + if not t then + txt, t = fetch(txt) + end + if t == v_default or t == v_normal then + align = saved_align + elseif t and t ~= "" then + align = "." .. t + end + elseif operation == "pb" then insert(pstack,variant) m = m + 1 ; metacode[m] = syntax.pb.direct if keys[special] == "text" and index then if keys["c"..special] == "text" then -- can be option: auto ... - m = m + 1 ; metacode[m] = format('chem_c%s(%s,%s,"");',special,bonds,index) + m = m + 1 ; metacode[m] = f_empty_center(special,variant,index) else - m = m + 1 ; metacode[m] = format('chem_%s(%s,%s,"");',special,bonds,index) + m = m + 1 ; metacode[m] = f_empty_normal(special,variant,index) end end + elseif operation == "pe" then + variant = remove(pstack) + local ss = syntax[variant] + keys, max = ss.keys, ss.max + m = m + 1 ; metacode[m] = syntax.pe.direct + m = m + 1 ; metacode[m] = f_set(variant) + current_variant = variant elseif operation == "save" then - insert(pstack,variant) + insert(sstack,variant) m = m + 1 ; metacode[m] = syntax.save.direct - elseif operation == "pe" or operation == "restore" then - variant = remove(pstack) + elseif operation == "restore" then + variant = remove(sstack) local ss = syntax[variant] - local prev = bonds or 6 - keys, bonds, max, rot = ss.keys, ss.n, ss.max, 1 - m = m + 1 ; metacode[m] = syntax[operation].direct - m = m + 1 ; metacode[m] = format("chem_set(%s,%s) ;",prev,bonds) - elseif operation == "front" then - if syntax[variant .. "_front"] then - variant = variant .. "_front" - local ss = syntax[variant] - local prev = bonds or 6 - keys, bonds, max, rot = ss.keys, ss.n, ss.max, 1 - m = m + 1 ; metacode[m] = format("chem_set(%s,%s) ;",prev,bonds) - end + keys, max = ss.keys, ss.max + m = m + 1 ; metacode[m] = syntax.restore.direct + m = m + 1 ; metacode[m] = f_set(variant) + current_variant = variant elseif operation then local ss = syntax[operation] + local what = keys[operation] + local ns = 0 + if set then + local sv = syntax[current_variant] + local ms = sv and sv.max + set = unique(set) + ns = #set + if directive_strictorder then + if what == "line" then + set = sorted(set) + end + if directive_strictindex and ms then + for i=ns,1,-1 do + local si = set[i] + if si > ms then + report_chemistry("level %a, operation %a, max nofsteps %a, ignoring %a",level,operation,ms,si) + set[i] = nil + ns = ns - 1 + else + break + end + end + end + else + if directive_strictindex and ms then + local t, nt = { }, 0 + for i=1,ns do + local si = set[i] + if si > ms then + report_chemistry("level %a, operation %a, max nofsteps %a, ignoring %a",level,operation,ms,si) + set[i] = nil + else + nt = nt + 1 + t[nt] = si + end + end + ns = nt + set = t + end + end + end if ss then local ds = ss.direct if ds then local sa = ss.arguments if sa == 1 then local one ; txt, one = fetch(txt) - m = m + 1 ; metacode[m] = format(ds,one or "") - elseif sa ==2 then + m = m + 1 ; metacode[m] = ds(one or "") + elseif sa == 2 then local one ; txt, one = fetch(txt) local two ; txt, two = fetch(txt) - m = m + 1 ; metacode[m] = format(ds,one or "",two or "") + m = m + 1 ; metacode[m] = ds(one or "",two or "") else m = m + 1 ; metacode[m] = ds end elseif ss.keys then - local prev = bonds or 6 - variant, keys, bonds, max, rot = s, ss.keys, ss.n, ss.max, 1 - m = m + 1 ; metacode[m] = format("chem_set(%s,%s) ;",prev,bonds) + variant, keys, max = s, ss.keys, ss.max + m = m + 1 ; metacode[m] = f_set(variant) + current_variant = variant end - else - local what = keys[operation] - if what == "line" then - if set then - for i=1,#set do - local si = set[i] - m = m + 1 ; metacode[m] = format("chem_%s(%s,%s,%s,%s,%s);",operation,bonds,si,si,rulethickness,rulecolor) + elseif what == "line" then + local s = osign + if s ~= "" then + s = "." .. s + end + if set then + -- condense consecutive numbers in a set to a range + local sf, st = set[1] + for i=1,ns do + if i > 1 and set[i] ~= set[i-1]+1 then + m = m + 1 ; metacode[m] = f_line(operation,s,variant,sf,st,rulethickness,rulecolor) + sf = set[i] end - elseif upto then - m = m + 1 ; metacode[m] = format("chem_%s(%s,%s,%s,%s,%s);",operation,bonds,index,upto,rulethickness,rulecolor) - elseif index then - m = m + 1 ; metacode[m] = format("chem_%s(%s,%s,%s,%s,%s);",operation,bonds,index,index,rulethickness,rulecolor) - else - m = m + 1 ; metacode[m] = format("chem_%s(%s,%s,%s,%s,%s);",operation,bonds,1,max,rulethickness,rulecolor) + st = set[i] end - elseif what == "number" then - if set then - for i=1,#set do - local si = set[i] - m = m + 1 ; metacode[m] = format('chem_%s(%s,%s,"\\chemicaltext{%s}");',operation,bonds,si,si) - end - elseif upto then - for i=index,upto do - local si = set[i] - m = m + 1 ; metacode[m] = format('chem_%s(%s,%s,"\\chemicaltext{%s}");',operation,bonds,si,si) - end - elseif index then - m = m + 1 ; metacode[m] = format('chem_%s(%s,%s,"\\chemicaltext{%s}");',operation,bonds,index,index) - else - for i=1,max do - m = m + 1 ; metacode[m] = format('chem_%s(%s,%s,"\\chemicaltext{%s}");',operation,bonds,i,i) - end + m = m + 1 ; metacode[m] = f_line(operation,s,variant,sf,st,rulethickness,rulecolor) + elseif upto then + m = m + 1 ; metacode[m] = f_line(operation,s,variant,index,upto,rulethickness,rulecolor) + elseif index then + m = m + 1 ; metacode[m] = f_line(operation,s,variant,index,index,rulethickness,rulecolor) + else + m = m + 1 ; metacode[m] = f_line(operation,s,variant,1,max,rulethickness,rulecolor) + end + elseif what == "number" then + if set then + for i=1,ns do + local si = set[i] + m = m + 1 ; metacode[m] = f_number(operation,align,variant,si,si) end - elseif what == "text" then - local align = syntax[variant].align - align = align and align[operation] - align = align and align[rot] - if set then - for i=1,#set do - local si = set[i] - local t = text - if not t then txt, t = fetch(txt) end - if t then - local a = align and align[si] - if a then a = "." .. a else a = "" end - t = molecule(processor_tostring(t)) - m = m + 1 ; metacode[m] = format('chem_%s%s(%s,%s,"\\chemicaltext{%s}");',operation,a,bonds,si,t) - end - end - elseif upto then - for i=index,upto do - local t = text - if not t then txt, t = fetch(txt) end - if t then - local s = align and align[i] - if s then s = "." .. s else s = "" end - t = molecule(processor_tostring(t)) - m = m + 1 ; metacode[m] = format('chem_%s%s(%s,%s,"\\chemicaltext{%s}");',operation,s,bonds,i,t) - end - end - elseif index == 0 then + elseif upto then + for i=index,upto do + local si = set[i] + m = m + 1 ; metacode[m] = f_number(operation,align,variant,si,si) + end + elseif index then + m = m + 1 ; metacode[m] = f_number(operation,align,variant,index,index) + else + for i=1,max do + m = m + 1 ; metacode[m] = f_number(operation,align,variant,i,i) + end + end + elseif what == "text" then + if set then + for i=1,ns do + local si = set[i] local t = text if not t then txt, t = fetch(txt) end if t then t = molecule(processor_tostring(t)) - m = m + 1 ; metacode[m] = format('chem_%s_zero("\\chemicaltext{%s}");',operation,t) + m = m + 1 ; metacode[m] = f_text(operation,align,variant,si,t) end - elseif index then + end + elseif upto then + for i=index,upto do local t = text if not t then txt, t = fetch(txt) end if t then - local s = align and align[index] - if s then s = "." .. s else s = "" end t = molecule(processor_tostring(t)) - m = m + 1 ; metacode[m] = format('chem_%s%s(%s,%s,"\\chemicaltext{%s}");',operation,s,bonds,index,t) - end - else - for i=1,max do - local t = text - if not t then txt, t = fetch(txt) end - if t then - local s = align and align[i] - if s then s = "." .. s else s = "" end - t = molecule(processor_tostring(t)) - m = m + 1 ; metacode[m] = format('chem_%s%s(%s,%s,"\\chemicaltext{%s}");',operation,s,bonds,i,t) - end + m = m + 1 ; metacode[m] = f_text(operation,align,variant,i,t) end end - elseif what == "transform" then - if index then - for r=1,rep do - m = m + 1 ; metacode[m] = format('chem_%s(%s,%s);',operation,bonds,index) - end - if operation == "rot" then - rot = index + elseif index == 0 then + local t = text + if not t then txt, t = fetch(txt) end + if t then + t = molecule(processor_tostring(t)) + m = m + 1 ; metacode[m] = f_text(operation,align,variant,index,t) + end + elseif index then + local t = text + if not t then txt, t = fetch(txt) end + if t then + t = molecule(processor_tostring(t)) + m = m + 1 ; metacode[m] = f_text(operation,align,variant,index,t) + end + else + for i=1,max do + local t = text + if not t then txt, t = fetch(txt) end + if t then + t = molecule(processor_tostring(t)) + m = m + 1 ; metacode[m] = f_text(operation,align,variant,i,t) end end - elseif what == "fixed" then - m = m + 1 ; metacode[m] = format("chem_%s(%s,%s,%s);",operation,bonds,rulethickness,rulecolor) end + elseif what == "transform" then + if osign == "m" then + factor = -factor + end + if set then + for i=1,ns do + local si = set[i] + m = m + 1 ; metacode[m] = f_transform(operation,variant,si,factor) + end + elseif upto then + for i=index,upto do + m = m + 1 ; metacode[m] = f_transform(operation,variant,i,factor) + end + else + m = m + 1 ; metacode[m] = f_transform(operation,variant,index or 1,factor) + end + elseif what == "fixed" then + m = m + 1 ; metacode[m] = f_transform(operation,variant,rulethickness,rulecolor) + elseif trace_structure then + report_chemistry("level %a, ignoring undefined operation %s",level,operation) end end end end remove(stack) + return current_variant end -- the size related values are somewhat special but we want to be -- compatible -- --- maybe we should default to fit --- -- rulethickness in points -function chemicals.start(settings) - chemicals.structures = chemicals.structures + 1 - local textsize, rulethickness, rulecolor = settings.size, settings.rulethickness, settings.rulecolor - local width, height, scale, offset = settings.width or 0, settings.height or 0, settings.scale or "medium", settings.offset or 0 - local l, r, t, b = settings.left or 0, settings.right or 0, settings.top or 0, settings.bottom or 0 - -- - metacode = { "if unknown context_chem : input mp-chem.mpiv ; fi ;" } -- no format anyway - -- - if scale == variables.small then - scale = 500 - elseif scale == variables.medium or scale == 0 then - scale = 625 - elseif scale == variables.big then - scale = 750 +local function checked(d,factor,unit,scale) + if d == v_none then + return 0 + end + local n = tonumber(d) + if not n then + -- assume dimen + elseif n >= 10 or n <= -10 then + return factor * unit * n / 1000 else - scale = tonumber(scale) - if not scale or scale == 0 then - scale = 750 - elseif scale < 10 then - scale = 10 - end + return factor * unit * n + end + local n = todimen(d) + if n then + return scale * n + else + return v_fit end - if width == variables.fit then - width = true +end + +local function calculated(height,bottom,top,factor,unit,scale) + if height == v_none then + -- this always wins + height = "0pt" + bottom = "0pt" + top = "0pt" + elseif height == v_fit then + height = "true" + bottom = bottom == v_fit and "true" or topoints(checked(bottom,factor,unit,scale)) + top = top == v_fit and "true" or topoints(checked(top, factor,unit,scale)) else - width = tonumber(width) or 0 - if l == 0 then - if r == 0 then - l = (width == 0 and 2000) or width/2 - r = l - elseif width ~= 0 then - l = width - r + height = checked(height,factor,unit,scale) + if bottom == v_fit then + if top == v_fit then + bottom = height / 2 + top = bottom + else + top = checked(top,factor,unit,scale) + bottom = height - top end - elseif r == 0 and width ~= 0 then - r = width - l + elseif top == v_fit then + bottom = checked(bottom,factor,unit,scale) + top = height - bottom + else + bottom = checked(bottom,factor,unit,scale) + top = checked(top, factor,unit,scale) + local ratio = height / (bottom+top) + bottom = bottom * ratio + top = top * ratio end - width = false + top = topoints(top) + bottom = topoints(bottom) + height = topoints(height) end - if height == variables.fit then - height = true + return height, bottom, top +end + +function chemistry.start(settings) + chemistry.structures = chemistry.structures + 1 + local unit = settings.unit or 655360 + local factor = settings.factor or 3 + local rulethickness = settings.rulethickness or 65536 + local rulecolor = settings.rulecolor or "" + local axiscolor = settings.framecolor or "" + local width = settings.width or v_fit + local height = settings.height or v_fit + local scale = settings.scale or "normal" + local rotation = settings.rotation or 0 + local offset = settings.offset or 0 + local left = settings.left or v_fit + local right = settings.right or v_fit + local top = settings.top or v_fit + local bottom = settings.bottom or v_fit + -- + metacode = { } + -- + align = settings.symalign or "auto" + if trace_structure then + report_chemistry("unit %p, factor %s, symalign %s",unit,factor,align) + end + if align ~= "" then + align = "." .. align + end + if trace_structure then + report_chemistry("%s scale %a, rotation %a, width %s, height %s, left %s, right %s, top %s, bottom %s","asked",scale,rotation,width,height,left,right,top,bottom) + end + if scale == v_small then + scale = 1/1.2 + elseif scale == v_normal or scale == v_medium or scale == 0 then + scale = 1 + elseif scale == v_big then + scale = 1.2 else - height = tonumber(height) or 0 - if t == 0 then - if b == 0 then - t = (height == 0 and 2000) or height/2 - b = t - elseif height ~= 0 then - t = height - b - end - elseif b == 0 and height ~= 0 then - b = height - t + scale = tonumber(scale) + if not scale or scale == 0 then + scale = 1 + elseif scale >= 10 then + scale = scale / 1000 + elseif scale < .01 then + scale = .01 end - height = false end - scale = 0.75 * scale/625 -- - metacode[#metacode+1] = format("chem_start_structure(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) ;", - chemicals.structures, - l/25, r/25, t/25, b/25, scale, - tostring(settings.axis == variables.on), tostring(width), tostring(height), tostring(offset) + unit = scale * unit + -- + width, left, right = calculated(width, left, right,factor,unit,scale) + height, bottom, top = calculated(height,bottom,top, factor,unit,scale) + -- + rotation = tonumber(rotation) or 0 + -- + if trace_structure then + report_chemistry("%s scale %a, rotation %a, width %s, height %s, left %s, right %s, top %s, bottom %s","used",scale,rotation,width,height,left,right,top,bottom) + end + metacode[#metacode+1] = f_start_structure( + chemistry.structures, + left, right, top, bottom, + rotation, topoints(unit), factor, topoints(offset), + tostring(settings.axis == v_on), topoints(rulethickness), tostring(axiscolor) ) + metacode[#metacode+1] = f_set_trace_bounds(trace_boundingbox) ; -- - variant, keys, bonds, stack, rot, pstack = "six", { }, 6, { }, 1, { } + variant, keys, stack, pstack, sstack = "one", { }, { }, { }, { } end -function chemicals.stop() - metacode[#metacode+1] = "chem_stop_structure ;" - -- +function chemistry.stop() + metacode[#metacode+1] = f_stop_structure local mpcode = concat(metacode,"\n") - if trace_structure then + if trace_metapost then report_chemistry("metapost code:\n%s", mpcode) end - metapost.graphic(chemicals.instance,chemicals.format,mpcode) + if metapost.instance(chemistry.instance) then + f_initialize = nil + end + metapost.graphic { + instance = chemistry.instance, + format = chemistry.format, + data = mpcode, + definitions = f_initialize, + } + t_initialize = "" metacode = nil end -function chemicals.component(spec,text,settings) +function chemistry.component(spec,text,settings) rulethickness, rulecolor, offset = settings.rulethickness, settings.rulecolor - local spec = settings_to_array(lower(spec)) - local text = settings_to_array(text) - metacode[#metacode+1] = "chem_start_component ;" - process(spec,text,1,rulethickness,rulecolor) - metacode[#metacode+1] = "chem_stop_component ;" + local spec = settings_to_array_with_repeat(spec,true) -- no lower? + local text = settings_to_array_with_repeat(text,true) +-- inspect(spec) + metacode[#metacode+1] = f_start_component + process(1,spec,text,1,rulethickness,rulecolor) -- offset? + metacode[#metacode+1] = f_stop_component end +statistics.register("chemical formulas", function() + if chemistry.structures > 0 then + return format("%s chemical structure formulas",chemistry.structures) -- no timing needed, part of metapost + end +end) + +-- interfaces + +commands.undefinechemical = chemistry.undefine +commands.definechemical = chemistry.define +commands.startchemical = chemistry.start +commands.stopchemical = chemistry.stop +commands.chemicalcomponent = chemistry.component + +-- todo: top / bottom +-- maybe add "=" for double and "≡" for triple? + local inline = { ["single"] = "\\chemicalsinglebond", ["-"] = "\\chemicalsinglebond", ["double"] = "\\chemicaldoublebond", ["--"] = "\\chemicaldoublebond", @@ -480,28 +781,20 @@ local inline = { ["gives"] = "\\chemicalgives", ["->"] = "\\chemicalgives", ["equilibrium"] = "\\chemicalequilibrium", ["<->"] = "\\chemicalequilibrium", ["mesomeric"] = "\\chemicalmesomeric", ["<>"] = "\\chemicalmesomeric", - ["plus"] = "\\chemicalsplus", ["+"] = "\\chemicalsplus", - ["minus"] = "\\chemicalsminus", - ["space"] = "\\chemicalsspace", + ["plus"] = "\\chemicalplus", ["+"] = "\\chemicalplus", + ["minus"] = "\\chemicalminus", + ["space"] = "\\chemicalspace", } --- todo: top / bottom - -function chemicals.inline(spec) - local spec = settings_to_array(spec) +function commands.inlinechemical(spec) + local spec = settings_to_array_with_repeat(spec,true) for i=1,#spec do local s = spec[i] local inl = inline[lower(s)] if inl then - context(inl) + context(inl) -- could be a fast context.sprint else context.chemicalinline(molecule(s)) end end end - -statistics.register("chemical formulas", function() - if chemicals.structures > 0 then - return format("%s chemical structure formulas",chemicals.structures) -- no timing needed, part of metapost - end -end) |