summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/chem-str.lua
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2013-04-08 00:43:40 +0000
committerKarl Berry <karl@freefriends.org>2013-04-08 00:43:40 +0000
commit824f7b0903de8ad7f6ee3d7656005e4c59155e06 (patch)
treeabfc8673ef9916f3ab7074e811207384c301492b /Master/texmf-dist/tex/context/base/chem-str.lua
parent689aefb0727676ed3cddf331337b4be226495e72 (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.lua957
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)