1if not modules then modules = { } end modules ['chem-str'] = {
2 version = 1.001,
3 comment = "companion to chem-str.mkiv",
4 author = "Hans Hagen and Alan Braslau",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26local trace_structure = false trackers .register("chemistry.structure", function(v) trace_structure = v end)
27local trace_metapost = false trackers .register("chemistry.metapost", function(v) trace_metapost = v end)
28local trace_boundingbox = false trackers .register("chemistry.boundingbox", function(v) trace_boundingbox = v end)
29local trace_textstack = false trackers .register("chemistry.textstack", function(v) trace_textstack = v end)
30local directive_strictorder = true directives.register("chemistry.strictorder", function(v) directive_strictorder = v end)
31local directive_strictindex = false directives.register("chemistry.strictindex", function(v) directive_strictindex = v end)
32
33local report_chemistry = logs.reporter("chemistry")
34
35local tonumber = tonumber
36local format, gmatch, match, lower, gsub = string.format, string.gmatch, string.match, string.lower, string.gsub
37local concat, insert, remove, unique, sorted = table.concat, table.insert, table.remove, table.unique, table.sorted
38local processor_tostring = typesetters and typesetters.processors.tostring
39local settings_to_array = utilities.parsers.settings_to_array
40local settings_to_array_with_repeat = utilities.parsers.settings_to_array_with_repeat
41
42local lpegmatch = lpeg.match
43local P, R, S, C, Cs, Ct, Cc, Cmt = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.Cc, lpeg.Cmt
44
45local variables = interfaces and interfaces.variables
46local commands = commands
47local context = context
48local implement = interfaces.implement
49
50local formatters = string.formatters
51
52local v_default = variables.default
53local v_small = variables.small
54local v_medium = variables.medium
55local v_big = variables.big
56local v_normal = variables.normal
57local v_fit = variables.fit
58local v_on = variables.on
59local v_none = variables.none
60
61local topoints = number.topoints
62local todimen = string.todimen
63
64local trialtypesetting = context.trialtypesetting
65
66chemistry = chemistry or { }
67local chemistry = chemistry
68
69chemistry.instance = "chemistry"
70chemistry.format = "metafun"
71chemistry.method = "double"
72
73local nofstructures = 0
74
75local common_keys = {
76 b = "line",
77 r = "line",
78 sb = "line",
79 sr = "line",
80 rd = "line",
81 rh = "line",
82 rb = "line",
83 rbd = "line",
84 cc = "line",
85 ccd = "line",
86 line = "line",
87 dash = "line",
88 arrow = "line",
89 c = "fixed",
90 cd = "fixed",
91 z = "text",
92 zt = "text",
93 zlt = "text",
94 zrt = "text",
95 rz = "text",
96 rt = "text",
97 lrt = "text",
98 rrt = "text",
99 label = "text",
100 zln = "number",
101 zrn = "number",
102 rn = "number",
103 lrn = "number",
104 rrn = "number",
105 zn = "number",
106 number = "number",
107 mov = "transform",
108 mark = "transform",
109 move = "transform",
110 diff = "transform",
111 off = "transform",
112 adj = "transform",
113 sub = "transform",
114}
115
116local front_keys = {
117 bb = "line",
118 eb = "line",
119 rr = "line",
120 lr = "line",
121 lsr = "line",
122 rsr = "line",
123 lrd = "line",
124 rrd = "line",
125 lrh = "line",
126 rrh = "line",
127 lrbd = "line",
128 rrbd = "line",
129 lrb = "line",
130 rrb = "line",
131 lrz = "text",
132 rrz = "text",
133 lsub = "transform",
134 rsub = "transform",
135}
136
137local one_keys = {
138 db = "line",
139 tb = "line",
140 bb = "line",
141 dr = "line",
142 hb = "line",
143 bd = "line",
144 bw = "line",
145 oe = "line",
146 sd = "line",
147 rdb = "line",
148 ldb = "line",
149 ldd = "line",
150 rdd = "line",
151 ep = "line",
152 es = "line",
153 ed = "line",
154 et = "line",
155 au = "line",
156 ad = "line",
157 cz = "text",
158 rot = "transform",
159 dir = "transform",
160 rm = "transform",
161 mir = "transform",
162}
163
164local ring_keys = {
165 db = "line",
166 hb = "line",
167 br = "line",
168 lr = "line",
169 rr = "line",
170 lsr = "line",
171 rsr = "line",
172 lrd = "line",
173 rrd = "line",
174 lrb = "line",
175 rrb = "line",
176 lrh = "line",
177 rrh = "line",
178 lrbd = "line",
179 rrbd = "line",
180 dr = "line",
181 eb = "line",
182 er = "line",
183 ed = "line",
184 au = "line",
185 ad = "line",
186 s = "line",
187 ss = "line",
188 mid = "line",
189 mids = "line",
190 midz = "text",
191 lrz = "text",
192 rrz = "text",
193 crz = "text",
194 rot = "transform",
195 mir = "transform",
196 adj = "transform",
197 lsub = "transform",
198 rsub = "transform",
199 rm = "transform",
200}
201
202
203
204
205
206
207
208front_keys = table.merged(front_keys,common_keys)
209one_keys = table.merged(one_keys,common_keys)
210ring_keys = table.merged(ring_keys,common_keys)
211
212local syntax = {
213 carbon = { max = 4, keys = one_keys, },
214 alkyl = { max = 4, keys = one_keys, },
215 newmanstagger = { max = 6, keys = one_keys, },
216 newmaneclipsed = { max = 6, keys = one_keys, },
217 one = { max = 8, keys = one_keys, },
218 three = { max = 3, keys = ring_keys, },
219 four = { max = 4, keys = ring_keys, },
220 five = { max = 5, keys = ring_keys, },
221 six = { max = 6, keys = ring_keys, },
222 seven = { max = 7, keys = ring_keys, },
223 eight = { max = 8, keys = ring_keys, },
224 nine = { max = 9, keys = ring_keys, },
225 fivefront = { max = 5, keys = front_keys, },
226 sixfront = { max = 6, keys = front_keys, },
227 chair = { max = 6, keys = front_keys, },
228 boat = { max = 6, keys = front_keys, },
229 pb = { direct = 'chem_pb;' },
230 pe = { direct = 'chem_pe;' },
231 save = { direct = 'chem_save;' },
232 restore = { direct = 'chem_restore;' },
233 chem = { direct = formatters['chem_symbol("\\chemicaltext{%s}");'], arguments = 1 },
234 space = { direct = 'chem_symbol("\\chemicalsymbol[space]");' },
235 plus = { direct = 'chem_symbol("\\chemicalsymbol[plus]");' },
236 minus = { direct = 'chem_symbol("\\chemicalsymbol[minus]");' },
237 equals = { direct = 'chem_symbol("\\chemicalsymbol[equals]");' },
238 gives = { direct = formatters['chem_symbol("\\chemicalsymbol[gives]{%s}{%s}");'], arguments = 2 },
239 equilibrium = { direct = formatters['chem_symbol("\\chemicalsymbol[equilibrium]{%s}{%s}");'], arguments = 2 },
240 mesomeric = { direct = formatters['chem_symbol("\\chemicalsymbol[mesomeric]{%s}{%s}");'], arguments = 2 },
241 opencomplex = { direct = 'chem_symbol("\\chemicalsymbol[opencomplex]");' },
242 closecomplex = { direct = 'chem_symbol("\\chemicalsymbol[closecomplex]");' },
243 reset = { direct = 'chem_reset;' },
244 mp = { direct = formatters['%s'], arguments = 1 },
245}
246
247chemistry.definitions = chemistry.definitions or { }
248local definitions = chemistry.definitions
249
250storage.register("chemistry/definitions",definitions,"chemistry.definitions")
251
252function chemistry.undefine(name)
253 definitions[lower(name)] = nil
254end
255
256function chemistry.define(name,spec,text)
257 name = lower(name)
258 local dn = definitions[name]
259 if not dn then
260 dn = { }
261 definitions[name] = dn
262 end
263 dn[#dn+1] = {
264 spec = settings_to_array_with_repeat(spec,true),
265 text = settings_to_array_with_repeat(text,true),
266 }
267end
268
269local metacode, variant, keys, max, txt, pstack, sstack, align
270local molecule = chemistry.molecule
271
272local function fetch(txt)
273 local st = stack[txt]
274 local t = st.text[st.n]
275 while not t and txt > 1 do
276 txt = txt - 1
277 st = stack[txt]
278 t = st.text[st.n]
279 end
280 if t then
281 if trace_textstack then
282 report_chemistry("fetching from stack %a, slot %a, data %a",txt,st.n,t)
283 end
284 st.n = st.n + 1
285 end
286 return txt, t
287end
288
289local remapper = {
290 ["+"] = "p",
291 ["-"] = "m",
292 ["--"] = "mm",
293 ["++"] = "pp",
294}
295
296local dchrs = R("09")
297local sign = S("+-")
298local digit = dchrs / tonumber
299local amount = (sign^-1 * (dchrs^0 * P('.'))^-1 * dchrs^1) / tonumber
300local single = digit
301local range = digit * P("..") * digit
302local set = Ct(digit^2)
303local colon = P(":")
304local equal = P("=")
305local other = 1 - digit - colon - equal
306local remapped = (sign * sign + sign) / remapper
307local operation = Cs(other^1)
308local special = (colon * C(other^1)) + Cc("")
309local text = (equal * C(P(1)^0)) + Cc(false)
310
311local pattern =
312 (amount + Cc(1))
313 * (remapped + Cc(""))
314 * Cs(operation/lower)
315 * Cs(special/lower) * (
316 range * Cc(false) * text +
317 Cc(false) * Cc(false) * set * text +
318 single * Cc(false) * Cc(false) * text +
319 Cc(false) * Cc(false) * Cc(false) * text
320 )
321
322
323
324
325
326
327
328
329local f_initialize = 'if unknown context_chem : input mp-chem.mpiv ; fi ;'
330local f_start_structure = formatters['chem_start_structure(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%q);']
331local f_set_trace_bounds = formatters['chem_trace_boundingbox := %l ;']
332local f_stop_structure = 'chem_stop_structure;'
333local f_start_component = 'chem_start_component;'
334local f_stop_component = 'chem_stop_component;'
335local f_line = formatters['chem_%s%s(%s,%s,%s,%s,%q);']
336local f_set = formatters['chem_set(%s);']
337local f_number = formatters['chem_%s%s(%s,%s,"\\chemicaltext{%s}");']
338local f_text = f_number
339local f_empty_normal = formatters['chem_%s(%s,%s,"");']
340local f_empty_center = formatters['chem_c%s(%s,%s,"");']
341local f_transform = formatters['chem_%s(%s,%s,%s);']
342local f_fixed = formatters['chem_%s(%s,%s,%q);']
343
344local function process(level,spec,text,n,rulethickness,rulecolor,offset,default_variant)
345 insert(stack,{ spec = spec, text = text, n = n })
346 local txt = #stack
347 local m = #metacode
348 local saved_rulethickness = rulethickness
349 local saved_rulecolor = rulecolor
350 local saved_align = align
351 local current_variant = default_variant or "six"
352 for i=1,#spec do
353 local step = spec[i]
354 local s = lower(step)
355 local n = current_variant .. ":" .. s
356 local d = definitions[n]
357 if not d then
358 n = s
359 d = definitions[n]
360 end
361 if d then
362 if trace_structure then
363 report_chemistry("level %a, step %a, definition %a, snippets %a",level,step,n,#d)
364 end
365 for i=1,#d do
366 local di = d[i]
367 current_variant = process(level+1,di.spec,di.text,1,rulethickness,rulecolor,offset,current_variant)
368 end
369 else
370 local factor, osign, operation, special, index, upto, set, text = lpegmatch(pattern,step)
371 if trace_structure then
372 local set = set and concat(set," ") or "-"
373 report_chemistry("level %a, step %a, factor %a, osign %a, operation %a, special %a, index %a, upto %a, set %a, text %a",
374 level,step,factor,osign,operation,special,index,upto,set,text)
375 end
376 if operation == "rulecolor" then
377 local t = text
378 if not t then
379 txt, t = fetch(txt)
380 end
381 if t == v_default or t == v_normal or t == "" then
382 rulecolor = saved_rulecolor
383 elseif t then
384 rulecolor = t
385 end
386 elseif operation == "rulethickness" then
387 local t = text
388 if not t then
389 txt, t = fetch(txt)
390 end
391 if t == v_default or t == v_normal or t == t_medium or t == "" then
392 rulethickness = saved_rulethickness
393 elseif t == v_small then
394 rulethickness = topoints(1/1.2 * todimen(saved_rulethickness))
395 elseif t == v_big then
396 rulethickness = topoints(1.2 * todimen(saved_rulethickness))
397 elseif t then
398
399 rulethickness = topoints(tonumber(t) * todimen(saved_rulethickness))
400 end
401 elseif operation == "symalign" then
402 local t = text
403 if not t then
404 txt, t = fetch(txt)
405 end
406 if t == v_default or t == v_normal then
407 align = saved_align
408 elseif t and t ~= "" then
409 align = "." .. t
410 end
411 elseif operation == "pb" then
412 insert(pstack,variant)
413 m = m + 1 ; metacode[m] = syntax.pb.direct
414 if keys[special] == "text" and index then
415 if keys["c"..special] == "text" then
416 m = m + 1 ; metacode[m] = f_empty_center(special,variant,index)
417 else
418 m = m + 1 ; metacode[m] = f_empty_normal(special,variant,index)
419 end
420 end
421 elseif operation == "pe" then
422 variant = remove(pstack)
423 local ss = syntax[variant]
424 keys, max = ss.keys, ss.max
425 m = m + 1 ; metacode[m] = syntax.pe.direct
426 m = m + 1 ; metacode[m] = f_set(variant)
427 current_variant = variant
428 elseif operation == "save" then
429 insert(sstack,variant)
430 m = m + 1 ; metacode[m] = syntax.save.direct
431 elseif operation == "restore" then
432 if #sstack > 0 then
433 variant = remove(sstack)
434 else
435 report_chemistry("restore without save")
436 end
437 local ss = syntax[variant]
438 keys, max = ss.keys, ss.max
439 m = m + 1 ; metacode[m] = syntax.restore.direct
440 m = m + 1 ; metacode[m] = f_set(variant)
441 current_variant = variant
442 elseif operation then
443 local ss = syntax[operation]
444 local what = keys[operation]
445 local ns = 0
446 if set then
447 local sv = syntax[current_variant]
448 local ms = sv and sv.max
449 set = unique(set)
450 ns = #set
451 if directive_strictorder then
452 if what == "line" then
453 set = sorted(set)
454 end
455 if directive_strictindex and ms then
456 for i=ns,1,-1 do
457 local si = set[i]
458 if si > ms then
459 report_chemistry("level %a, operation %a, max nofsteps %a, ignoring %a",level,operation,ms,si)
460 set[i] = nil
461 ns = ns - 1
462 else
463 break
464 end
465 end
466 end
467 else
468 if directive_strictindex and ms then
469 local t, nt = { }, 0
470 for i=1,ns do
471 local si = set[i]
472 if si > ms then
473 report_chemistry("level %a, operation %a, max nofsteps %a, ignoring %a",level,operation,ms,si)
474 set[i] = nil
475 else
476 nt = nt + 1
477 t[nt] = si
478 end
479 end
480 ns = nt
481 set = t
482 end
483 end
484 end
485 if ss then
486 local ds = ss.direct
487 if ds then
488 local sa = ss.arguments
489 if sa == 1 then
490 local one ; txt, one = fetch(txt)
491 m = m + 1 ; metacode[m] = ds(one or "")
492 elseif sa == 2 then
493 local one ; txt, one = fetch(txt)
494 local two ; txt, two = fetch(txt)
495 m = m + 1 ; metacode[m] = ds(one or "",two or "")
496 else
497 m = m + 1 ; metacode[m] = ds
498 end
499 elseif ss.keys then
500 variant, keys, max = s, ss.keys, ss.max
501 m = m + 1 ; metacode[m] = f_set(variant)
502 current_variant = variant
503 end
504 elseif what == "line" then
505 local s = osign
506 if s ~= "" then
507 s = "." .. s
508 end
509 if set then
510
511 local sf, st = set[1]
512 for i=1,ns do
513 if i > 1 and set[i] ~= set[i-1]+1 then
514 m = m + 1 ; metacode[m] = f_line(operation,s,variant,sf,st,rulethickness,rulecolor)
515 sf = set[i]
516 end
517 st = set[i]
518 end
519 m = m + 1 ; metacode[m] = f_line(operation,s,variant,sf,st,rulethickness,rulecolor)
520 elseif upto then
521 m = m + 1 ; metacode[m] = f_line(operation,s,variant,index,upto,rulethickness,rulecolor)
522 elseif index then
523 m = m + 1 ; metacode[m] = f_line(operation,s,variant,index,index,rulethickness,rulecolor)
524 else
525 m = m + 1 ; metacode[m] = f_line(operation,s,variant,1,max,rulethickness,rulecolor)
526 end
527 elseif what == "number" then
528 if set then
529 for i=1,ns do
530 local si = set[i]
531 m = m + 1 ; metacode[m] = f_number(operation,align,variant,si,si)
532 end
533 elseif upto then
534 for i=index,upto do
535 local si = set[i]
536 m = m + 1 ; metacode[m] = f_number(operation,align,variant,si,si)
537 end
538 elseif index then
539 m = m + 1 ; metacode[m] = f_number(operation,align,variant,index,index)
540 else
541 for i=1,max do
542 m = m + 1 ; metacode[m] = f_number(operation,align,variant,i,i)
543 end
544 end
545 elseif what == "text" then
546 if set then
547 for i=1,ns do
548 local si = set[i]
549 local t = text
550 if not t then txt, t = fetch(txt) end
551 if t then
552 t = molecule(processor_tostring(t))
553
554
555 m = m + 1 ; metacode[m] = f_text(operation,align,variant,si,t)
556 end
557 end
558 elseif upto then
559 for i=index,upto do
560 local t = text
561 if not t then txt, t = fetch(txt) end
562 if t then
563 t = molecule(processor_tostring(t))
564 m = m + 1 ; metacode[m] = f_text(operation,align,variant,i,t)
565 end
566 end
567 elseif index == 0 then
568 local t = text
569 if not t then txt, t = fetch(txt) end
570 if t then
571 t = molecule(processor_tostring(t))
572 m = m + 1 ; metacode[m] = f_text(operation,align,variant,index,t)
573 end
574 elseif index then
575 local t = text
576 if not t then txt, t = fetch(txt) end
577 if t then
578 t = molecule(processor_tostring(t))
579 m = m + 1 ; metacode[m] = f_text(operation,align,variant,index,t)
580 end
581 else
582 for i=1,max do
583 local t = text
584 if not t then txt, t = fetch(txt) end
585 if t then
586 t = molecule(processor_tostring(t))
587 m = m + 1 ; metacode[m] = f_text(operation,align,variant,i,t)
588 end
589 end
590 end
591 elseif what == "transform" then
592 if osign == "m" then
593 factor = -factor
594 end
595 if set then
596 for i=1,ns do
597 local si = set[i]
598 m = m + 1 ; metacode[m] = f_transform(operation,variant,si,factor)
599 end
600 elseif upto then
601 for i=index,upto do
602 m = m + 1 ; metacode[m] = f_transform(operation,variant,i,factor)
603 end
604 else
605 m = m + 1 ; metacode[m] = f_transform(operation,variant,index or 1,factor)
606 end
607 elseif what == "fixed" then
608 m = m + 1 ; metacode[m] = f_fixed(operation,variant,rulethickness,rulecolor)
609 elseif trace_structure then
610 report_chemistry("level %a, ignoring undefined operation %s",level,operation)
611 end
612 end
613 end
614 end
615 remove(stack)
616 return current_variant
617end
618
619
620
621
622
623
624local function checked(d,bondlength,unit,scale)
625 if d == v_none then
626 return 0
627 end
628 local n = tonumber(d)
629 if not n then
630
631 elseif n >= 10 or n <= -10 then
632 return bondlength * unit * n / 1000
633 else
634 return bondlength * unit * n
635 end
636 local n = todimen(d)
637 if n then
638 return scale * n
639 else
640 return v_fit
641 end
642end
643
644local function calculated(height,bottom,top,bondlength,unit,scale)
645 local scaled = 0
646 if height == v_none then
647
648 height = "0pt"
649 bottom = "0pt"
650 top = "0pt"
651 elseif height == v_fit then
652 height = "true"
653 bottom = bottom == v_fit and "true" or topoints(checked(bottom,bondlength,unit,scale))
654 top = top == v_fit and "true" or topoints(checked(top, bondlength,unit,scale))
655 else
656 height = checked(height,bondlength,unit,scale)
657 if bottom == v_fit then
658 if top == v_fit then
659 bottom = height / 2
660 top = bottom
661 else
662 top = checked(top,bondlength,unit,scale)
663 bottom = height - top
664 end
665 elseif top == v_fit then
666 bottom = checked(bottom,bondlength,unit,scale)
667 top = height - bottom
668 else
669 bottom = checked(bottom,bondlength,unit,scale)
670 top = checked(top, bondlength,unit,scale)
671 local ratio = height / (bottom+top)
672 bottom = bottom * ratio
673 top = top * ratio
674 end
675 scaled = height
676 top = topoints(top)
677 bottom = topoints(bottom)
678 height = topoints(height)
679 end
680 return height, bottom, top, scaled
681end
682
683function chemistry.start(settings)
684
685 local width = settings.width or v_fit
686 local height = settings.height or v_fit
687 local unit = settings.unit or 655360
688 local bondlength = settings.factor or 3
689 local rulethickness = settings.rulethickness or 65536
690 local rulecolor = settings.rulecolor or "black"
691 local axiscolor = settings.framecolor or "black"
692 local scale = settings.scale or "normal"
693 local rotation = settings.rotation or 0
694 local offset = settings.offset or 0
695 local left = settings.left or v_fit
696 local right = settings.right or v_fit
697 local top = settings.top or v_fit
698 local bottom = settings.bottom or v_fit
699
700 align = settings.symalign or "auto"
701 if trace_structure then
702 report_chemistry("unit %p, bondlength %s, symalign %s",unit,bondlength,align)
703 end
704 if align ~= "" then
705 align = "." .. align
706 end
707 if trace_structure then
708 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)
709 end
710 if scale == v_small then
711 scale = 1/1.2
712 elseif scale == v_normal or scale == v_medium or scale == 0 then
713 scale = 1
714 elseif scale == v_big then
715 scale = 1.2
716 else
717 scale = tonumber(scale)
718 if not scale or scale == 0 then
719 scale = 1
720 elseif scale >= 10 then
721 scale = scale / 1000
722 elseif scale < .01 then
723 scale = .01
724 end
725 end
726
727 unit = scale * unit
728
729 local sp_width = 0
730 local sp_height = 0
731
732 width, left, right, sp_width = calculated(width, left, right,bondlength,unit,scale)
733 height, bottom, top, sp_height = calculated(height,bottom,top, bondlength,unit,scale)
734
735 if width ~= "true" and height ~= "true" and trialtypesetting() then
736 if trace_structure then
737 report_chemistry("skipping trial run")
738 end
739 context.rule(sp_width,sp_height,0)
740 return
741 end
742
743 nofstructures = nofstructures + 1
744
745 rotation = tonumber(rotation) or 0
746
747 metacode = { }
748
749 if trace_structure then
750 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)
751 end
752 metacode[#metacode+1] = f_start_structure(
753 nofstructures,
754 left, right, top, bottom,
755 rotation, topoints(unit), bondlength, scale, topoints(offset),
756 tostring(settings.axis == v_on), topoints(rulethickness), axiscolor
757 )
758 metacode[#metacode+1] = f_set_trace_bounds(trace_boundingbox) ;
759
760 variant, keys, stack, pstack, sstack = "one", { }, { }, { }, { }
761end
762
763function chemistry.stop()
764 if metacode then
765 metacode[#metacode+1] = f_stop_structure
766 local mpcode = concat(metacode,"\n")
767 if trace_metapost then
768 report_chemistry("metapost code:\n%s", mpcode)
769 end
770 metapost.graphic {
771 instance = chemistry.instance,
772 format = chemistry.format,
773 method = chemistry.method,
774 data = mpcode,
775 definitions = f_initialize,
776 }
777 metacode = nil
778 end
779end
780
781function chemistry.component(spec,text,rulethickness,rulecolor)
782 if metacode then
783 local spec = settings_to_array_with_repeat(spec,true)
784 local text = settings_to_array_with_repeat(text,true)
785 metacode[#metacode+1] = f_start_component
786 process(1,spec,text,1,rulethickness,rulecolor)
787 metacode[#metacode+1] = f_stop_component
788 end
789end
790
791statistics.register("chemical formulas", function()
792 if nofstructures > 0 then
793 return format("%s chemical structure formulas",nofstructures)
794 end
795end)
796
797
798
799implement {
800 name = "undefinechemical",
801 actions = chemistry.undefine,
802 arguments = "string"
803}
804
805implement {
806 name = "definechemical",
807 actions = chemistry.define,
808 arguments = "3 strings",
809}
810
811implement {
812 name = "startchemical",
813 actions = chemistry.start,
814 arguments = {
815 {
816 { "width" },
817 { "height" },
818 { "left" },
819 { "right" },
820 { "top" },
821 { "bottom" },
822 { "scale" },
823 { "rotation" },
824 { "symalign" },
825 { "axis" },
826 { "framecolor" },
827 { "rulethickness" },
828 { "offset" },
829 { "unit" },
830 { "factor" }
831 }
832 }
833}
834
835implement {
836 name = "stopchemical",
837 actions = chemistry.stop,
838}
839
840implement {
841 name = "chemicalcomponent",
842 actions = chemistry.component,
843 arguments = "4 strings",
844}
845
846
847
848
849local inline = {
850 ["single"] = "\\chemicalsinglebond", ["-"] = "\\chemicalsinglebond",
851 ["double"] = "\\chemicaldoublebond", ["--"] = "\\chemicaldoublebond",
852 ["="] = "\\chemicaldoublebond",
853 ["triple"] = "\\chemicaltriplebond", ["---"] = "\\chemicaltriplebond",
854 ["≡"] = "\\chemicaltriplebond",
855 ["gives"] = "\\chemicalgives", ["->"] = "\\chemicalgives",
856 ["equilibrium"] = "\\chemicalequilibrium", ["<-->"] = "\\chemicalequilibrium",
857 ["<=>"] = "\\chemicalequilibrium",
858 ["mesomeric"] = "\\chemicalmesomeric", ["<>"] = "\\chemicalmesomeric",
859 ["<->"] = "\\chemicalmesomeric",
860 ["plus"] = "\\chemicalplus", ["+"] = "\\chemicalplus",
861 ["minus"] = "\\chemicalminus",
862 ["equals"] = "\\chemicalequals",
863 ["space"] = "\\chemicalspace",
864}
865
866local ctx_chemicalinline = context.chemicalinline
867
868function chemistry.inlinechemical(spec)
869 local spec = settings_to_array_with_repeat(spec,true)
870 for i=1,#spec do
871 local s = spec[i]
872 local inl = inline[lower(s)]
873 if inl then
874 context(inl)
875 else
876 ctx_chemicalinline(molecule(s))
877 end
878 end
879end
880
881implement {
882 name = "inlinechemical",
883 actions = chemistry.inlinechemical,
884 arguments = "string"
885}
886 |