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 |