summaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-11-26 03:00:45 +0000
committerNorbert Preining <norbert@preining.info>2019-11-26 03:00:45 +0000
commitbd1c54bb99e58d8c140acb0b0a536037f96349b4 (patch)
treea819ef21fdb386c28b7becb459d3adfdde0fce15 /graphics
parent447c94ee79e6bd2ecba4c822e4c07763b492747e (diff)
CTAN sync 201911260300
Diffstat (limited to 'graphics')
-rw-r--r--graphics/mol2chemfig/README32
-rw-r--r--graphics/mol2chemfig/doc/doc-source/chapters/installation.tex43
-rw-r--r--graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/chemfig-settings.tex10
-rw-r--r--graphics/mol2chemfig/doc/mol2chemfig-doc.pdfbin234181 -> 0 bytes
-rw-r--r--graphics/mol2chemfig/docs/README1
-rw-r--r--graphics/mol2chemfig/docs/chapters/abstract.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/abstract.tex)10
-rw-r--r--graphics/mol2chemfig/docs/chapters/arrows.tex2
-rw-r--r--graphics/mol2chemfig/docs/chapters/atom-numbers.tex19
-rw-r--r--graphics/mol2chemfig/docs/chapters/bond-lengths.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/bond-lengths.tex)4
-rw-r--r--graphics/mol2chemfig/docs/chapters/compatibility.tex5
-rw-r--r--graphics/mol2chemfig/docs/chapters/composite.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/composite.tex)12
-rw-r--r--graphics/mol2chemfig/docs/chapters/conclusion.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/conclusion.tex)10
-rw-r--r--graphics/mol2chemfig/docs/chapters/context.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/context.tex)2
-rw-r--r--graphics/mol2chemfig/docs/chapters/crossing-bonds.tex23
-rw-r--r--graphics/mol2chemfig/docs/chapters/flip-rotate.tex16
-rw-r--r--graphics/mol2chemfig/docs/chapters/help.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/help.tex)0
-rw-r--r--graphics/mol2chemfig/docs/chapters/hydrogens.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/hydrogens.tex)4
-rw-r--r--graphics/mol2chemfig/docs/chapters/input-modes.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/input-modes.tex)0
-rw-r--r--graphics/mol2chemfig/docs/chapters/installation.tex39
-rw-r--r--graphics/mol2chemfig/docs/chapters/introduction.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/introduction.tex)0
-rw-r--r--graphics/mol2chemfig/docs/chapters/output.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/output.tex)0
-rw-r--r--graphics/mol2chemfig/docs/chapters/polishing.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/polishing.tex)2
-rw-r--r--graphics/mol2chemfig/docs/chapters/recalculating.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/recalculating.tex)0
-rw-r--r--graphics/mol2chemfig/docs/chapters/submolecules.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/submolecules.tex)2
-rw-r--r--graphics/mol2chemfig/docs/chapters/tpic1.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/tpic1.tex)0
-rw-r--r--graphics/mol2chemfig/docs/chapters/tpic2.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/tpic2.tex)4
-rw-r--r--graphics/mol2chemfig/docs/chapters/tpic3.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/tpic3.tex)0
-rw-r--r--graphics/mol2chemfig/docs/chapters/tutorial.tex (renamed from graphics/mol2chemfig/doc/doc-source/chapters/tutorial.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/atcc.mol (renamed from graphics/mol2chemfig/doc/doc-source/examples/atcc.mol)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/atcc.sh1
-rw-r--r--graphics/mol2chemfig/docs/examples/atcc.tex36
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/buildscripts.sh43
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/caffeine-from-smiles-rotated.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/caffeine-from-smiles-rotated.sh)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/caffeine-from-smiles.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/caffeine-from-smiles.sh)0
-rw-r--r--graphics/mol2chemfig/docs/examples/caffeine-smi.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/caffeine-smi.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/caffeine-smi2.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/caffeine-smi2.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/caffeine.mol (renamed from graphics/mol2chemfig/doc/doc-source/examples/caffeine.mol)0
-rw-r--r--graphics/mol2chemfig/docs/examples/caffeine.smi (renamed from graphics/mol2chemfig/doc/doc-source/examples/caffeine.smi)0
-rw-r--r--graphics/mol2chemfig/docs/examples/ce-submol1.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/ce-submol1.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/ce-submol2.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/ce-submol2.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/ce-submol3.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/ce-submol3.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/crown-ether.mol (renamed from graphics/mol2chemfig/doc/doc-source/examples/crown-ether.mol)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/cubane-cross-n.sh1
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/cubane-cross.sh1
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/cubane-n.sh1
-rw-r--r--graphics/mol2chemfig/docs/examples/cubane-n.tex25
-rw-r--r--graphics/mol2chemfig/docs/examples/cubane.mol (renamed from graphics/mol2chemfig/doc/doc-source/examples/cubane.mol)0
-rw-r--r--graphics/mol2chemfig/docs/examples/cubane.sdf140
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/cubane.sh1
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/daptomycin-u.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/daptomycin-u.sh)0
-rw-r--r--graphics/mol2chemfig/docs/examples/daptomycin-u.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/daptomycin-u.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/daptomycin.mol (renamed from graphics/mol2chemfig/doc/doc-source/examples/daptomycin.mol)0
-rw-r--r--graphics/mol2chemfig/docs/examples/daptomycin.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/daptomycin.tex)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/daptomycin1.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/daptomycin1.sh)0
-rw-r--r--graphics/mol2chemfig/docs/examples/dcf-submol1.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/dcf-submol1.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/dcf-submol2.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/dcf-submol2.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/dcf-submol3.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/dcf-submol3.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/dichlorofluorescein.mol (renamed from graphics/mol2chemfig/doc/doc-source/examples/dichlorofluorescein.mol)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/dichlorofluorescein1.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/dichlorofluorescein1.sh)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/dichlorofluorescein2.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/dichlorofluorescein2.sh)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/dichlorofluorescein3.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/dichlorofluorescein3.sh)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/doxo-from-sdf.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/doxo-from-sdf.sh)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/doxo-hand-rotated.sh1
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/doxo-numbered.sh1
-rw-r--r--graphics/mol2chemfig/docs/examples/doxo-numbered.tex74
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/doxo-ratcheted-rotated.sh1
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/doxo-ratcheted.sh1
-rw-r--r--graphics/mol2chemfig/docs/examples/doxo-raw.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/doxo-raw.tex)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/doxo-recalculated-flopped.sh1
-rw-r--r--graphics/mol2chemfig/docs/examples/doxo-recalculated-flopped.tex74
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/doxo-recalculated-rotated.sh1
-rw-r--r--graphics/mol2chemfig/docs/examples/doxo-recalculated-rotated.tex74
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/doxo-recalculated.sh1
-rw-r--r--graphics/mol2chemfig/docs/examples/doxo-recalculated.tex74
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/doxo-strip-h.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/doxo-strip-h.sh)0
-rw-r--r--graphics/mol2chemfig/docs/examples/doxo-stripped.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/doxo-stripped.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/doxorubicin.sdf264
-rw-r--r--graphics/mol2chemfig/docs/examples/eschers-cubane.tex33
-rw-r--r--graphics/mol2chemfig/docs/examples/fmnh.mol (renamed from graphics/mol2chemfig/doc/doc-source/examples/fmnh.mol)0
-rw-r--r--graphics/mol2chemfig/docs/examples/hand-coded-tex/aspirin.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/aspirin.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/hand-coded-tex/caffeine.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/caffeine.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/hand-coded-tex/chemfig-settings.tex15
-rw-r--r--graphics/mol2chemfig/docs/examples/hand-coded-tex/sodium-green.png (renamed from graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/sodium-green.png)bin45165 -> 45165 bytes
-rw-r--r--graphics/mol2chemfig/docs/examples/hand-coded-tex/sodium-green1.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/sodium-green1.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/hand-coded-tex/sodium-green2.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/sodium-green2.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/hand-coded-tex/sodium-green3.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/sodium-green3.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/hand-coded-tex/stuff.tex8
-rw-r--r--graphics/mol2chemfig/docs/examples/hand-coded-tex/twisted-commented.tex25
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/morphine-f.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/morphine-f.sh)0
-rw-r--r--graphics/mol2chemfig/docs/examples/morphine-f.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/morphine-f.tex)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/morphine-k.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/morphine-k.sh)0
-rw-r--r--graphics/mol2chemfig/docs/examples/morphine-k.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/morphine-k.tex)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/morphine-n.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/morphine-n.sh)0
-rw-r--r--graphics/mol2chemfig/docs/examples/morphine-n.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/morphine-n.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/morphine.mol (renamed from graphics/mol2chemfig/doc/doc-source/examples/morphine.mol)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/morphine.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/morphine.sh)0
-rw-r--r--graphics/mol2chemfig/docs/examples/morphine.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/morphine.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/mp.mol (renamed from graphics/mol2chemfig/doc/doc-source/examples/mp.mol)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/mp.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/mp.sh)0
-rw-r--r--graphics/mol2chemfig/docs/examples/mp.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/mp.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/mp06900.pdfbin0 -> 224528 bytes
-rw-r--r--graphics/mol2chemfig/docs/examples/optionlist.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/optionlist.tex)2
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/packmoles.sh1
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/phenol-add-h.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/phenol-add-h.sh)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/phenol-as-submol.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/phenol-as-submol.sh)0
-rw-r--r--graphics/mol2chemfig/docs/examples/phenol-as-submol.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/phenol-as-submol.tex)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/phenol-from-smiles-w.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/phenol-from-smiles-w.sh)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/phenol-from-smiles-wz.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/phenol-from-smiles-wz.sh)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/phenol-from-smiles.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/phenol-from-smiles.sh)0
-rw-r--r--graphics/mol2chemfig/docs/examples/phenol-smi-terse.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/phenol-smi-terse.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/phenol-smi-wrapped.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/phenol-smi-wrapped.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/phenol-smi.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/phenol-smi.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/phenol-with-hydrogens.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/phenol-with-hydrogens.tex)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/plp-arrows.sh2
-rw-r--r--graphics/mol2chemfig/docs/examples/plp.mol (renamed from graphics/mol2chemfig/doc/doc-source/examples/plp.mol)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/plp.sh (renamed from graphics/mol2chemfig/doc/doc-source/examples/plp.sh)0
-rw-r--r--graphics/mol2chemfig/docs/examples/plp.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/plp.tex)0
-rw-r--r--graphics/mol2chemfig/docs/examples/plp2.mol (renamed from graphics/mol2chemfig/doc/doc-source/examples/plp2.mol)0
-rw-r--r--graphics/mol2chemfig/docs/examples/plp2.tex (renamed from graphics/mol2chemfig/doc/doc-source/examples/plp2.tex)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/printoptions.sh1
-rw-r--r--graphics/mol2chemfig/docs/examples/setbondstyle.tex2
-rw-r--r--graphics/mol2chemfig/docs/examples/twisted.mol (renamed from graphics/mol2chemfig/doc/doc-source/examples/twisted.mol)0
-rwxr-xr-xgraphics/mol2chemfig/docs/examples/twisted.sh3
-rw-r--r--graphics/mol2chemfig/docs/mol2chemfig-doc.tex (renamed from graphics/mol2chemfig/doc/doc-source/mol2chemfig-doc.tex)3
-rw-r--r--graphics/mol2chemfig/docs/preamble.tex (renamed from graphics/mol2chemfig/doc/doc-source/preamble.tex)6
-rw-r--r--graphics/mol2chemfig/docs/test.tex20
-rw-r--r--graphics/mol2chemfig/install/mol2chemfig-1.5/PKG-INFO10
-rwxr-xr-xgraphics/mol2chemfig/install/mol2chemfig-1.5/mol2chemfig13
-rw-r--r--graphics/mol2chemfig/install/mol2chemfig-1.5/mol2chemfig.cmd7
-rw-r--r--graphics/mol2chemfig/install/mol2chemfig-1.5/setup.py14
-rw-r--r--graphics/mol2chemfig/install/mol2chemfig-1.5/src/__init__.py1
-rw-r--r--graphics/mol2chemfig/install/mol2chemfig-1.5/src/atom.py183
-rw-r--r--graphics/mol2chemfig/install/mol2chemfig-1.5/src/bond.py558
-rw-r--r--graphics/mol2chemfig/install/mol2chemfig-1.5/src/chemfig_mappings.py487
-rw-r--r--graphics/mol2chemfig/install/mol2chemfig-1.5/src/common.py109
-rw-r--r--graphics/mol2chemfig/install/mol2chemfig-1.5/src/molecule.py702
-rw-r--r--graphics/mol2chemfig/install/mol2chemfig-1.5/src/optionparser.py458
-rw-r--r--graphics/mol2chemfig/install/mol2chemfig-1.5/src/options.py236
-rw-r--r--graphics/mol2chemfig/install/mol2chemfig-1.5/src/processor.py212
-rw-r--r--graphics/mol2chemfig/latex/mol2chemfig.sty (renamed from graphics/mol2chemfig/doc/doc-source/mol2chemfig.sty)63
-rw-r--r--graphics/mol2chemfig/lua/README78
-rw-r--r--graphics/mol2chemfig/lua/json.lua417
-rwxr-xr-xgraphics/mol2chemfig/lua/mol2chemfig.lua12
-rw-r--r--graphics/mol2chemfig/lua/mol2chemfig_client_1_2.lua (renamed from graphics/mol2chemfig/lua/mol2chemfig_client.lua)14
-rw-r--r--graphics/mol2chemfig/lua/mol2chemfig_dkjson.lua646
-rw-r--r--graphics/mol2chemfig/lua/mol2chemfig_jsonrpc.lua86
-rw-r--r--graphics/mol2chemfig/lua/rpc.lua105
-rw-r--r--graphics/mol2chemfig/mol2chemfig-doc.pdfbin0 -> 229324 bytes
-rw-r--r--graphics/mol2chemfig/sampledoc/README_SAMPLEDOC (renamed from graphics/mol2chemfig/sampledoc/README)0
-rw-r--r--graphics/mol2chemfig/sampledoc/fmn.mol71
-rw-r--r--graphics/mol2chemfig/sampledoc/mol2chemfig.sty236
-rw-r--r--graphics/mol2chemfig/sampledoc/penicilling.mol53
-rw-r--r--graphics/mol2chemfig/sampledoc/plp.mol48
-rw-r--r--graphics/mol2chemfig/sampledoc/plp2.mol48
-rw-r--r--graphics/mol2chemfig/sampledoc/plp3.tex45
-rw-r--r--graphics/mol2chemfig/sampledoc/plp3highlighted.tex40
-rw-r--r--graphics/mol2chemfig/sampledoc/plpmarked.tex38
-rw-r--r--graphics/mol2chemfig/sampledoc/sample.pdfbin102918 -> 101802 bytes
-rw-r--r--graphics/mol2chemfig/sampledoc/sample.tex5
-rw-r--r--graphics/mol2chemfig/sampledoc/weg.pdfbin0 -> 101703 bytes
-rw-r--r--graphics/mol2chemfig/sampledoc/weg.tex210
-rw-r--r--graphics/mol2chemfig/tex/mol2chemfig.sty236
-rw-r--r--graphics/pgf/contrib/dynkin-diagrams/DoneTwoElBendy.tex5
-rw-r--r--graphics/pgf/contrib/dynkin-diagrams/DoneTwoElStraight.tex6
-rw-r--r--graphics/pgf/contrib/dynkin-diagrams/EulerProducts.tex61
-rw-r--r--graphics/pgf/contrib/dynkin-diagrams/README9
-rw-r--r--graphics/pgf/contrib/dynkin-diagrams/borovoi.tex15
-rw-r--r--graphics/pgf/contrib/dynkin-diagrams/d44.tex19
-rw-r--r--graphics/pgf/contrib/dynkin-diagrams/dynkin-diagrams.pdfbin744590 -> 0 bytes
-rw-r--r--graphics/pgf/contrib/dynkin-diagrams/dynkin-diagrams.sty36
-rw-r--r--graphics/pgf/contrib/dynkin-diagrams/dynkin-diagrams.tex114
-rw-r--r--graphics/pgf/contrib/dynkin-diagrams/hermitian-symmetric-spaces.tex19
-rw-r--r--graphics/pgf/contrib/dynkin-diagrams/simple-lie-algebras.tex35
173 files changed, 5463 insertions, 1474 deletions
diff --git a/graphics/mol2chemfig/README b/graphics/mol2chemfig/README
index 852ee5f125..b6aa266218 100644
--- a/graphics/mol2chemfig/README
+++ b/graphics/mol2chemfig/README
@@ -1,4 +1,4 @@
-mol2chemfig 1.4
+mol2chemfig 1.5
---------------
mol2chemfig is a Python program to convert chemical structures
@@ -7,8 +7,9 @@ by the chemfig package. Its home page is at
http://chimpsky.uwaterloo.ca/mol2chemfig/
-This folder contains all available files for installing mol2chemfig
-on your computer.
+This folder contains all files required for installing mol2chemfig
+on your computer, as well as the PDF documentation and its source
+files.
Licence
@@ -20,13 +21,12 @@ Free (LaTeX Project Licence, see http://www.latex-project.org/lppl/)
Requirements
------------
-mol2chemfig needs a working Python version 2.x install.
-At the time of this writing, the most recent Python 2.x version is
-Python 2.7. The program should also work with other recent 2.x versions,
-however.
+mol2chemfig needs a working Python version 2.x install. At the time of this
+writing, the most recent Python 2.x version is Python 2.7. The program should
+also work with other recent 2.x versions, however.
In addition, mol2chemfig requires indigo toolkit for Python. The installation
-procedures of these prerequisites vary with your platform; in Linux,
+procedures of these prerequisites vary with your platform. On Linux,
your package manager will likely be able to satisfy all requirements.
Otherwise, visit python.org for Python and ggasoftware.com for indigo.
@@ -57,18 +57,24 @@ reasons, and most likely I can not figure them out from the other side
of the world. Instead, go buy a beer for your resident
Mac/Windows/Linux/WhatEver guru.
+As an alternative to full local installation, you can also use the
+lua web-client script that simply calls the mol2chemfig server for each
+work request. This is explained in more detail in a separate README in
+the 'lua' folder.
Usage
-----
-The 'latex' folder contains a sample document with several included
-mol2chemfig-generated chemfig code files. It also contains the
-mol2chemfig.sty LaTeX package that is required to compile any
+The 'sampledoc' folder contains a sample document with several
+included mol2chemfig-generated chemfig code files. It also contains
+the mol2chemfig.sty LaTeX package that is required to compile any
documents using mol2chemfig-generated chemfig code, including
-code generated through the mol2chemfig web interface.
+code generated through the mol2chemfig web interface. A copy of that
+file is also in the 'tex' folder. Move this file to a location
+where your LaTeX setup will find it.
Bugs?
-----
-Thought so. Please send bug reports to mpalmer@uwaterloo.ca. \ No newline at end of file
+Thought so. Please send bug reports to mpalmer@uwaterloo.ca.
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/installation.tex b/graphics/mol2chemfig/doc/doc-source/chapters/installation.tex
deleted file mode 100644
index afd900f9db..0000000000
--- a/graphics/mol2chemfig/doc/doc-source/chapters/installation.tex
+++ /dev/null
@@ -1,43 +0,0 @@
-\section{Installation}
-
-There are three ways to run \mcf:
-%
-\begin{inparaenum}
-\item You can use the web interface.
-\item You can install a web client version of \mcf that is operated from the command line.
-\item You can install the entire program locally.
-\end{inparaenum}
-
-With options 1 and 2, everything you need can hopefully be installed via TeXLive by the time you read this. In contrast, with option 3, some additional handiwork is required.
-
-Update: \mcf has been on CTAN for a good while now, but as far as I can tell adoption into TeXLive has not happened, and apparently isn't going to.
-
-\subsection{\LaTeX\ requirements}
-
-In order to use the code generated by \mcf in your documents, you need
-
-\begin{enumerate}
-\item \tkz, a large and powerful general graphics package.
-
-\item \chf, which defines the code format used by \mcf and uses \tkz to render it to molecule graphics.
-
-\item The \texttt{mol2chemfig.sty} package. This is a very small package that defines some auxiliary macros for \mcf.
-\end{enumerate}
-
-\tkz and \chf are available through TeXLive, and \mcf is or will hopefully soon be, too. Note that the \mcf package will load the \chf package for you, which in turn loads \tkz. Therefore, in your documents, it is sufficient to include the clause \lstinline!\usepackage{mol2chemfig}! in order to load all three of them.
-
-\subsection{Installing the Lua web client}
-
-The web client should be installed and properly configured when you install \mcf through TeXLive; this is the preferred method. You should be able to invoke it from a shell window (or command prompt, in Windows parlance) with the command
-
-\begin{lstlisting}
-$ mol2chemfig.lua
-\end{lstlisting}
-
-If you downloaded the \mcf bundle from CTAN, no automatic installation is performed. In that case, follow the instructions in the included README file.
-
-\subsection{Local installation}
-
-For the full local install of \mcf, you need a Python base installation, and additionally the \texttt{indigo} cheminformatics toolkit. On at least some Linux distributions, \texttt{indigo} is available through the package manager. On other systems, manual download (\url{http://ggasoftware.com/download/indigo}) and installation may be required.
-
-Once you have the prerequisites installed and working, download the \mcf Python code from \url{http://chimpsky.uwaterloo.ca/mol2chemfig}, unzip in a convenient location and follow the included instructions.
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/chemfig-settings.tex b/graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/chemfig-settings.tex
deleted file mode 100644
index cffe37c1df..0000000000
--- a/graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/chemfig-settings.tex
+++ /dev/null
@@ -1,10 +0,0 @@
-% reduce font size and use sans-serif
-\renewcommand{\printatom}[1]{%
-\fontsize{8pt}{10pt}\selectfont{\ensuremath{\mathsf{#1}}}}
-
-% reduce bond dimensions to match smaller fonts
-\setcrambond{2.5pt}{0.4pt}{1.0pt}
-\setbondoffset{1pt}
-\setdoublesep{2pt}
-\setatomsep{16pt}
-
diff --git a/graphics/mol2chemfig/doc/mol2chemfig-doc.pdf b/graphics/mol2chemfig/doc/mol2chemfig-doc.pdf
deleted file mode 100644
index f11c215602..0000000000
--- a/graphics/mol2chemfig/doc/mol2chemfig-doc.pdf
+++ /dev/null
Binary files differ
diff --git a/graphics/mol2chemfig/docs/README b/graphics/mol2chemfig/docs/README
new file mode 100644
index 0000000000..735ebf5d8c
--- /dev/null
+++ b/graphics/mol2chemfig/docs/README
@@ -0,0 +1 @@
+The files in this directory are the sources for the main documentation file.
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/abstract.tex b/graphics/mol2chemfig/docs/chapters/abstract.tex
index 46c9600106..9b07a8d001 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/abstract.tex
+++ b/graphics/mol2chemfig/docs/chapters/abstract.tex
@@ -3,11 +3,9 @@
%
The program is available
%
-\begin{inparaenum}[a)]
-\item through a web interface,
-\item for local installation, and
-\item as a command line-driven thin client.
-\end{inparaenum}
+a) through a web interface,
+b) for local installation, and
+c) as a command line-driven thin client.
%
-The thin client is a Lua script that is designed to work with recent TeXLive installations.
+The thin client is a Lua script that is designed to work with the Lua interpreted embedded in LuaTeX, which is part of all recent TeXLive versions.
\end{abstract}
diff --git a/graphics/mol2chemfig/docs/chapters/arrows.tex b/graphics/mol2chemfig/docs/chapters/arrows.tex
new file mode 100644
index 0000000000..c41097ac0e
--- /dev/null
+++ b/graphics/mol2chemfig/docs/chapters/arrows.tex
@@ -0,0 +1,2 @@
+\subsection{Attaching electron flow arrows}
+
diff --git a/graphics/mol2chemfig/docs/chapters/atom-numbers.tex b/graphics/mol2chemfig/docs/chapters/atom-numbers.tex
new file mode 100644
index 0000000000..e80db27d5b
--- /dev/null
+++ b/graphics/mol2chemfig/docs/chapters/atom-numbers.tex
@@ -0,0 +1,19 @@
+\subsection{Displaying atom numbers}
+
+% well this is a steaming pile. What do I do with this? A better use of displaying atom numbers is in connection with cross bonds. Let's go for those, then.
+
+
+If we look closely at the second doxorubicin graphic above, we notice that some bonds aren't quite straight but are veering slightly off course. In order to fix that up manually, we would need to correlate the atoms in the generated \texttt{.tex} file with the graphic. To do so, we display their numbers with the \lstinline!--atom-numbers! or \lstinline!-n! option:
+
+\lstinputlisting{doxo-numbered.sh}
+
+which gives
+
+\cfpic{doxo-numbered.tex}
+
+Let's say we want to straighten out the double bonds that point to atom no.\ 9 and no.\ 10. We delve into the previously generated, unnumbered version of the file and locate the atoms (only a fragment of the file is shown):
+
+\lstinputlisting[firstline=37,lastline=48]{doxo-stripped.tex}
+
+We see that the bond angles slightly deviate from multiples of 90 degrees in both cases. Indeed, slightly inaccurate angles are seen all over the file; fixing them all would be tedious. Instead, we can simply ask \mcf to recalculate the coordinates for us.
+
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/bond-lengths.tex b/graphics/mol2chemfig/docs/chapters/bond-lengths.tex
index d5993637e4..edf4f00f19 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/bond-lengths.tex
+++ b/graphics/mol2chemfig/docs/chapters/bond-lengths.tex
@@ -7,10 +7,10 @@ There are two mechanisms with which we can explicitly change the bond lengths:
\begin{enumerate}
\item Within \mcf, you can use the \lstinline!--bond-scale! or \lstinline!-s! option, usually in combination with the \lstinline!--bond-stretch! or \lstinline!-t! option.
-\item Within \chf, you can set the unit bond length---that is, the length of a bond whose length is equals 1 inside the \lstinline!\chemfig! macro---with \chf's \lstinline!\setatomsep! macro.
+\item Within \chf, you can set the unit bond length with e.g.\ \lstinline!\setchemfig{atom sep=16pt}!. This sets the length of a bond whose length is equals 1 (the default) inside the \lstinline!\chemfig! macro.
\end{enumerate}
-The \lstinline!\setatomsep! approach is straightforward; in this document, \lstinline!\setatomsep{16pt}! has been used throughout. The two \mcf options need a bit more explaining. The \lstinline!--bond-scale! or \lstinline!-s! option defines \mcf's overall behavior:
+The \lstinline!\setchemfig! approach is straightforward; in this document, \lstinline!\setchemfig{atom sep=16pt}! has been used throughout. The two \mcf options need a bit more explaining. The \lstinline!--bond-scale! or \lstinline!-s! option defines \mcf's overall behavior:
\begin{itemize}
\item With a setting of \lstinline!--bond-scale=keep!, \mcf will leave the bond lengths entirely alone; the \lstinline!--bond-stretch! option will have no effect in this case.
diff --git a/graphics/mol2chemfig/docs/chapters/compatibility.tex b/graphics/mol2chemfig/docs/chapters/compatibility.tex
new file mode 100644
index 0000000000..c3d4bb39b1
--- /dev/null
+++ b/graphics/mol2chemfig/docs/chapters/compatibility.tex
@@ -0,0 +1,5 @@
+\section{\chf version compatibility}
+
+Earlier versions of \chf used a series of named macros to adjust various parameters, for example \lstinline!\setatomsep{...}! to set the regular distance between two atoms in a rendered molecule. In recent versions of the package, these macros have been replaced with a unified key-value interface that employs a single macro, e.g.: \lstinline!\setchemfig{atom sep=...}!. There is at least one transitional \chf version (1.34, which I happen to have installed as of this writing) that understands both.
+
+The \texttt{mol2chemfig.sty} version that accompanies this documentation works only with \chf versions which use the \lstinline!\setchemfig{...}! interface. If your chemfig version is old and does not have this macro, then you can download a matching, older version from the \mcf \href{http://chimpsky.uwaterloo.ca/mol2chemfig/download}{home page}. If you have installed the \mcf program or the Lua client locally, you don't need to downgrade those; the required change only affects the \mcf LaTeX package. \ No newline at end of file
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/composite.tex b/graphics/mol2chemfig/docs/chapters/composite.tex
index 492c241ef5..db2ffc84ce 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/composite.tex
+++ b/graphics/mol2chemfig/docs/chapters/composite.tex
@@ -4,11 +4,11 @@ The \texttt{mol2chemfig} package loads \texttt{chemfig}, which in turn loads the
\input{chapters/tpic1}
-The code for this graphics is
+The code for this graphic is
\lstinputlisting{chapters/tpic1}
-The two structures were placed on the canvas using \tkz nodes. The \tkz nodes cannot contain \lstinline!\input! macros. Therefore, as a workaround, we render the structures as submol definitions with
+The two structures were placed on the canvas using \tkz nodes. The \tkz nodes cannot contain \lstinline!\input! macros. Therefore, as a workaround, we first render the structures as submol definitions with
\lstinputlisting{plp.sh}
@@ -34,7 +34,7 @@ which gives
One important thing to note is that, when the overlay mechanism is used, the document has to be processed \emph{twice} by pdftex---otherwise, the overlaid elements tend to get misaligned.
-The \lstinline!\draw! commands used in the example for the electron push arrows employed the \lstinline!mcfpusharrow! \tkz style that is defined by the \mcf package. You can adjust this style to your own tastes with the \lstinline!\tikzset! macro.
+The \lstinline!\draw! commands used in the example for the electron push arrows employed the \lstinline!mcfpusharrow! \tkz style that is defined by the \mcf package. You can adjust this style to your own tastes with the \lstinline!\tikzset! macro; see the \tkz documentation for details.
If the push-arrows are the \emph{only} drawing element you need, you can avoid the need for explicitly creating an overlaid second \lstinline!tikzpicture! environment by using macros predefined by either \chf and \mcf. The next example illustrates the use of the \lstinline!\mcfpush! macro defined by \mcf.
@@ -44,7 +44,9 @@ which gives
\input{chapters/tpic3}
-The arguments of the \lstinline!\mcfpush! macro are, in order, the named anchor of the origin, the parameters of the first control point (departure angle:distance), and the second anchor and second control point (arrival angle:distance). Two optional arguments set the \lstinline!shorten <=! and \lstinline!shorten >=! lengths for the arrow in question, which override the global values which can be adjusted using the \lstinline!\tikzset! mechanism. The \lstinline!\mcfpush! macro uses the \lstinline!mcfpusharrow! \tkz style (see above). This style references two color definitions, which were redefined using \lstinline!colorlet! (supplied by package \lstinline!xcolor!) in this example. The background color (\lstinline!mcfbgcolor!) defaults to white; you will only want to change it when drawing on a non-white canvas. This color definition is also used when drawing crossing bonds in the foreground (see section \ref{sec:tweaking}).
+The arguments of the \lstinline!\mcfpush! macro are, in order, the named anchor of the origin, the parameters of the first control point (departure angle:distance), and the second anchor and second control point (arrival angle:distance). Two optional arguments set the \lstinline!shorten <=! and \lstinline!shorten >=! lengths for the arrow in question, which override the global values that can be adjusted using the \lstinline!\tikzset! mechanism.
-Note that internally the picture overlay mechanism is still used, so the need for processing the file through pdftex twice remains.
+The \lstinline!\mcfpush! macro uses the \lstinline!mcfpusharrow! \tkz style (see above). This style references two color definitions, which were redefined using \lstinline!colorlet! (supplied by package \lstinline!xcolor!) in this example. The background color (\lstinline!mcfbgcolor!) defaults to white; you will only want to change it when drawing on a non-white canvas. This color definition is also used when drawing crossing bonds in the foreground (see section \ref{sec:tweaking}).
+
+Note that, even though the the overlaid \lstinline!tikzpicture! environment is no longer explicitly declared, the overlay mechanism is still used internally, so the need for processing the file with \TeX\ twice remains.
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/conclusion.tex b/graphics/mol2chemfig/docs/chapters/conclusion.tex
index 693129481a..ef88bf7f10 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/conclusion.tex
+++ b/graphics/mol2chemfig/docs/chapters/conclusion.tex
@@ -10,7 +10,7 @@ Using the \lstinline!--shell-escape! option on Linux or its equivalents on other
\mcfinput{-fw examples/fmnh.mol}
\end{center}
-\noindent Note, however, that with large documents and numerous formulas the overhead of running \texttt{mol2chemfig} on each formula during every compilation will add up.
+\noindent Note, however, that with large documents and numerous chemical structures the overhead of running \texttt{mol2chemfig} on each formula during every compilation will add up.
\section{\texttt{chemfig} settings used in this document}
\label{sec:ChemfigSettings}
@@ -27,9 +27,11 @@ I hope \mcf will be useful to you. If you come across any bugs or issues, please
\section{Acknowledgments}
-Christian Tellechea wrote the excellent \chf package, upon which \mcf is based. He also gave valuable advice and suggestions concerning \mcf itself. To the extent that \mcf understands chemistry, it owes this to the creators of \texttt{indigo}. An earlier version of \mcf used \texttt{rdkit}; however, after some experimentation, I found that \texttt{indigo} was better suited to my purpose. Nevertheless, I thank \texttt{rdkit}'s creator, Greg Landrum, for promptly and thoroughly answering all my questions.
-%
-My student Eric Brefo-Mensah tested the code extensively and uncovered numerous bugs (or rather, a whole plague of locusts). Further bugs were reported by Benjamin Abel, Philipp Bisson, and Vincent Liegeois.
+Christian Tellechea wrote the excellent \chf package, upon which \mcf is based. He also gave valuable help concerning \mcf itself; he solved several problems for me that had me stumped. He is the author of a French book on TeX; if you read French, you should probably get a copy.
+
+To the extent that \mcf understands chemistry, it owes this to the creators of \texttt{indigo}. An earlier version of \mcf used \texttt{rdkit}; however, after some experimentation, I found that \texttt{indigo} was better suited to my purpose. Nevertheless, I thank \texttt{rdkit}'s creator, Greg Landrum, for promptly and thoroughly answering all my questions.
+
+My (now former) student Eric Brefo-Mensah tested the code extensively and uncovered numerous bugs (or rather, a whole plague of locusts). Further bugs were reported by Benjamin Abel, Philipp Bisson, and Vincent Liegeois.
%
% A big thank you to everyone.
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/context.tex b/graphics/mol2chemfig/docs/chapters/context.tex
index f05692f986..95ed624913 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/context.tex
+++ b/graphics/mol2chemfig/docs/chapters/context.tex
@@ -1,5 +1,5 @@
\subsection{ConTeXt compatibility}
-Currently not available.
+Currently not available. Volunteers for porting welcome.
%\tkz and \chf are both compatible with ConTeXt. I don't know the first thing about ConTeXt myself, but thankfully Christian Tellechea, the author of \chf, has provided a plain-\TeX\ file with macros that should allow \mcf to work with ConTeXt. This file, \mcfplain, is also included with the archive and should be installed alongside \chf.
diff --git a/graphics/mol2chemfig/docs/chapters/crossing-bonds.tex b/graphics/mol2chemfig/docs/chapters/crossing-bonds.tex
new file mode 100644
index 0000000000..a6066ad023
--- /dev/null
+++ b/graphics/mol2chemfig/docs/chapters/crossing-bonds.tex
@@ -0,0 +1,23 @@
+\subsection{Crossing bonds}
+
+The cubane molecule contains several bonds that cross each other:
+
+\lstinputlisting{cubane-n.sh}
+
+\cfpic{cubane-n.tex}
+
+Use the \lstinline!--cross-bond! or \lstinline!-k! option to specify which bonds should go into the foreground:
+
+\lstinputlisting{cubane-cross-n.sh}
+
+\cfpic{eschers-cubane.tex}
+
+The implementation of this feature is a bit of a hack, I'm afraid; the following code listing (with hand-written comments) illustrates the contortions it adds to the generated code.
+
+\lstinputlisting{hand-coded-tex/twisted-commented.tex}
+
+The styling of the bond in the foreground can be adjusted by tweaking the \lstinline!mcfcrossbond! \tkz key in the \lstinline!mol2chemfig.sty! package. Alternatively, as of version 1.2b, \lstinline!mol2chemfig.sty! patches \chf's \lstinline!\setbondstyle! macro, such that the background for crossing bonds can be passed as an optional argument:
+
+\lstinputlisting{setbondstyle.tex}\input{setbondstyle.tex}
+
+\cfpic{eschers-cubane.tex}
diff --git a/graphics/mol2chemfig/docs/chapters/flip-rotate.tex b/graphics/mol2chemfig/docs/chapters/flip-rotate.tex
new file mode 100644
index 0000000000..8857af4857
--- /dev/null
+++ b/graphics/mol2chemfig/docs/chapters/flip-rotate.tex
@@ -0,0 +1,16 @@
+\subsection{Flipping and rotating structures}
+
+The vertical flipping can be reverted by passing the option \lstinline!--flop! or \lstinline!-q!:
+
+\lstinputlisting{doxo-recalculated-flopped.sh}
+
+\cfpic{doxo-recalculated-flopped.tex}
+
+Horizontal flipping is done with option \lstinline!--flip! or \lstinline!-p!.
+
+Rotation is performed by passing the \lstinline!--angle! or \lstinline!-a! option; rotation is counter-clockwise:
+
+\lstinputlisting{doxo-recalculated-rotated.sh}
+
+\cfpic{doxo-recalculated-rotated.tex}
+
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/help.tex b/graphics/mol2chemfig/docs/chapters/help.tex
index b38ca5df9c..b38ca5df9c 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/help.tex
+++ b/graphics/mol2chemfig/docs/chapters/help.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/hydrogens.tex b/graphics/mol2chemfig/docs/chapters/hydrogens.tex
index 0f1d4fdfa4..4bf7f16592 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/hydrogens.tex
+++ b/graphics/mol2chemfig/docs/chapters/hydrogens.tex
@@ -6,11 +6,11 @@ The next example renders an SDF file for doxorubicin, downloaded from PubChem%
\lstinputlisting{doxo-from-sdf.sh}
-This gives us (yikes)
+This gives us
\cfpic{doxo-raw.tex}
-Let's remove the explicit hydrogens with option \lstinline!--hydrogens=delete! or \lstinline!-y delete!:
+Yikes. Let's remove the explicit hydrogens with option \lstinline!--hydrogens=delete! or \lstinline!-y delete!:
\lstinputlisting{doxo-strip-h.sh}
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/input-modes.tex b/graphics/mol2chemfig/docs/chapters/input-modes.tex
index 75e60f79cd..75e60f79cd 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/input-modes.tex
+++ b/graphics/mol2chemfig/docs/chapters/input-modes.tex
diff --git a/graphics/mol2chemfig/docs/chapters/installation.tex b/graphics/mol2chemfig/docs/chapters/installation.tex
new file mode 100644
index 0000000000..0671439af9
--- /dev/null
+++ b/graphics/mol2chemfig/docs/chapters/installation.tex
@@ -0,0 +1,39 @@
+\section{Installation}
+
+There are three ways to run \mcf:
+%
+\begin{enumerate}
+\item You can use the web interface at \url{http://chimpsky.uwaterloo.ca/mol2chemfig/}
+\item You can install the entire program locally and run it from the command line. This requires that you also install Python and the indigo cheminformatics library.
+\item You can install a web client version of \mcf that is operated from the command line. This is a little program written entirely in Lua, which can be run by the \texttt{texlua} executable that is part of TeXLive.
+\end{enumerate}
+
+\subsection{\LaTeX\ requirements}
+
+In order to use the code generated by \mcf in your documents, you need
+
+\begin{enumerate}
+\item \tkz, a large and powerful general graphics package.
+
+\item \chf, which defines the code format used by \mcf and uses \tkz to render it to molecule graphics.
+
+\item The \texttt{mol2chemfig.sty} package. This is a fairly small package that defines some auxiliary macros for \mcf.
+
+Version 1.3 of \chf changed its interface for setting options; e.g.\ \verb|\setatomsep{16pt}| has been replaced by \verb|\setchemfig{atom sep=16pt}|. The current version of the \mcf package has been brought up to date with this change. I will leave an old version of the \mcf package up on my website (see web interface, above), which you can use in case you have to or want to use an older version of \chf.
+
+\end{enumerate}
+
+\tkz and \chf are available through TeXLive. Note that the \mcf package will load the \chf package for you, which in turn loads \tkz. Therefore, in your documents, it is sufficient to include the clause \lstinline!\usepackage{mol2chemfig}! in order to load all three of them.
+
+\subsection{Local installation}
+
+For the full local install of \mcf, you need a Python base installation, and additionally the \texttt{indigo} cheminformatics tool kit. On at least some Linux distributions, \texttt{indigo} is available through the package manager. On other systems, manual download (\url{http://lifescience.opensource.epam.com/indigo/index.html}) and installation may be required.
+
+Once you have the prerequisites installed and working, download the \mcf Python code from CTAN or from \url{http://chimpsky.uwaterloo.ca/mol2chemfig}, unzip in a convenient location and follow the included instructions.
+
+\subsection{Installing the Lua web client}
+
+% no need to repeat this here.
+This is a Lua script that lets you use the \mcf from the command line, but without having to install any additional libraries. For instructions, please see the instructions in the included README file that is within the \texttt{lua} subdirectory contained within the \mcf download.
+
+
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/introduction.tex b/graphics/mol2chemfig/docs/chapters/introduction.tex
index ad260ca6dd..ad260ca6dd 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/introduction.tex
+++ b/graphics/mol2chemfig/docs/chapters/introduction.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/output.tex b/graphics/mol2chemfig/docs/chapters/output.tex
index 9db9450716..9db9450716 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/output.tex
+++ b/graphics/mol2chemfig/docs/chapters/output.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/polishing.tex b/graphics/mol2chemfig/docs/chapters/polishing.tex
index 481cde81e6..7b00af9641 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/polishing.tex
+++ b/graphics/mol2chemfig/docs/chapters/polishing.tex
@@ -17,7 +17,7 @@ which gives
\cfpic{morphine-f.tex}
-Note that the look of the double bonds involves some \tkz trickery; in the generated code, the double bonds are no longer represented by \lstinline!=! symbols but instead by something like \lstinline!-[:120,,,,drh]!. Also note that, for this to work, you need the current version of the \mcf \LaTeX\ package.
+Note that the look of the double bonds involves some \tkz trickery; in the generated code, the double bonds are no longer represented by \lstinline!=! symbols but instead by something like \lstinline!-[:120,,,,drh]!.
Next, the molecule contains two bonds that cross each other, and we would like to draw the vertical one in the foreground. To specify this bond, we need the numbers of the adjoining atoms. We first can let \mcf print the atom numbers:
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/recalculating.tex b/graphics/mol2chemfig/docs/chapters/recalculating.tex
index 04a6bf428c..04a6bf428c 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/recalculating.tex
+++ b/graphics/mol2chemfig/docs/chapters/recalculating.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/submolecules.tex b/graphics/mol2chemfig/docs/chapters/submolecules.tex
index c4ef14ada1..2509962799 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/submolecules.tex
+++ b/graphics/mol2chemfig/docs/chapters/submolecules.tex
@@ -24,7 +24,7 @@ which gives us the following fabulous result:
\cfpic{hand-coded-tex/sodium-green1}
-What went wrong here? Submol expansion is essentially string substitution. When the submol is filled in, the connection to the preceding part of the molecule is made by whatever atom happens to have been rendered first, and the last rendered atom connects to the subsequent parts of the structure. So, we need to tell \mcf the order in which to render the atoms. To identify the atoms that we want to join, we display all atom numbers in the structure.
+What went wrong here? Submol expansion is essentially string substitution. When the submol is filled in, the connection to the preceding part of the molecule is made by whichever atom happens to have been rendered first, and the last rendered atom of the submol connects to the subsequent parts of the structure. Thus, we need to tell \mcf the order in which to render the atoms. To identify the atoms that we want to join, we display all atom numbers in the structure.
\lstinputlisting[firstline=2]{dichlorofluorescein2.sh}
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/tpic1.tex b/graphics/mol2chemfig/docs/chapters/tpic1.tex
index b6cbf60595..b6cbf60595 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/tpic1.tex
+++ b/graphics/mol2chemfig/docs/chapters/tpic1.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/tpic2.tex b/graphics/mol2chemfig/docs/chapters/tpic2.tex
index 6280b5af20..901594b2b3 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/tpic2.tex
+++ b/graphics/mol2chemfig/docs/chapters/tpic2.tex
@@ -15,7 +15,7 @@
\draw[mcfpusharrow](mp12-13) to [out=60,in=60,looseness=4] (mp11-12);
\draw[mcfpusharrow](mp2-3) to [out=105,in=105,looseness=5] (mp3);
-% attach some arbitrary shapes
-\draw[semithick,blue,fill=red](mp17) -- ++(0.3,0.3) arc (-135:225:0.2);
+% attach some arbitrary shapes to the molecule
+\draw[semithick,blue,fill=red](mp17) -- ++(0.5,0.5) node[circle,fill=yellow,inner sep=1pt,draw=blue]{\scriptsize\textsf{blob}};
\end{tikzpicture}
\end{center}
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/tpic3.tex b/graphics/mol2chemfig/docs/chapters/tpic3.tex
index 82567ec23c..82567ec23c 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/tpic3.tex
+++ b/graphics/mol2chemfig/docs/chapters/tpic3.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/chapters/tutorial.tex b/graphics/mol2chemfig/docs/chapters/tutorial.tex
index ddf8c9ef82..ddf8c9ef82 100644
--- a/graphics/mol2chemfig/doc/doc-source/chapters/tutorial.tex
+++ b/graphics/mol2chemfig/docs/chapters/tutorial.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/atcc.mol b/graphics/mol2chemfig/docs/examples/atcc.mol
index f89a2c3c99..f89a2c3c99 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/atcc.mol
+++ b/graphics/mol2chemfig/docs/examples/atcc.mol
diff --git a/graphics/mol2chemfig/docs/examples/atcc.sh b/graphics/mol2chemfig/docs/examples/atcc.sh
new file mode 100755
index 0000000000..12c6dbc3e0
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/atcc.sh
@@ -0,0 +1 @@
+mol2chemfig -w atcc.mol > atcc.tex \ No newline at end of file
diff --git a/graphics/mol2chemfig/docs/examples/atcc.tex b/graphics/mol2chemfig/docs/examples/atcc.tex
new file mode 100644
index 0000000000..9507eeacc9
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/atcc.tex
@@ -0,0 +1,36 @@
+\chemfig{
+ O% 2
+ =[:149.3]% 12
+ (
+ -[:89.3]% 13
+ (
+ -[:29.3]% 15
+ =_[:89.3]% 16
+ -[:29.3]% 18
+ =_[:329.3]% 20
+ -[:269.3]% 19
+ =_[:209.3]% 17
+ -[:149.3]% -> 15
+ )
+ -[:149.3]% 14
+ -[:89.3,,,1]OH% 3
+ )
+ -[:209.3]O% 1
+ -[:150]% 11
+ -[:96]% 9
+ -[:160.2,2.065]% 5
+ -[:53.1,1.228]% 4
+ (
+ -[:65.5]% 21
+ )
+ =^[:257.9,2.285]% 6
+ (
+ -[:315.8,1.22]% 10
+ -[:24]% -> 11
+ )
+ -[:193.9,1.225]% 8
+ -[:105]% 7
+ (
+ -[:26,1.323]% -> 5
+ )
+}
diff --git a/graphics/mol2chemfig/docs/examples/buildscripts.sh b/graphics/mol2chemfig/docs/examples/buildscripts.sh
new file mode 100755
index 0000000000..a4ddb132ec
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/buildscripts.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+chmod +x ./*.sh
+
+# ./twisted.sh
+
+# ./cubane.sh
+# ./cubane-cross.sh
+./cubane-n.sh
+./cubane-cross-n.sh
+
+./caffeine-from-smiles.sh
+./caffeine-from-smiles-rotated.sh
+
+./daptomycin1.sh
+./daptomycin-u.sh
+
+./printoptions.sh
+
+./phenol-from-smiles.sh
+./phenol-from-smiles-w.sh
+./phenol-from-smiles-wz.sh
+./phenol-as-submol.sh
+./phenol-add-h.sh
+
+./doxo-from-sdf.sh
+./doxo-strip-h.sh
+./doxo-numbered.sh
+./doxo-recalculated.sh
+./doxo-recalculated-flopped.sh
+./doxo-recalculated-rotated.sh
+
+./dichlorofluorescein1.sh
+./dichlorofluorescein2.sh
+./dichlorofluorescein3.sh
+
+./morphine.sh
+./morphine-f.sh
+./morphine-n.sh
+./morphine-k.sh
+
+./plp.sh
+
+./mp.sh \ No newline at end of file
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/caffeine-from-smiles-rotated.sh b/graphics/mol2chemfig/docs/examples/caffeine-from-smiles-rotated.sh
index 328348612c..328348612c 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/caffeine-from-smiles-rotated.sh
+++ b/graphics/mol2chemfig/docs/examples/caffeine-from-smiles-rotated.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/caffeine-from-smiles.sh b/graphics/mol2chemfig/docs/examples/caffeine-from-smiles.sh
index 33899ea052..33899ea052 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/caffeine-from-smiles.sh
+++ b/graphics/mol2chemfig/docs/examples/caffeine-from-smiles.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/caffeine-smi.tex b/graphics/mol2chemfig/docs/examples/caffeine-smi.tex
index 2aa7e08f8c..2aa7e08f8c 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/caffeine-smi.tex
+++ b/graphics/mol2chemfig/docs/examples/caffeine-smi.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/caffeine-smi2.tex b/graphics/mol2chemfig/docs/examples/caffeine-smi2.tex
index 25a670d931..25a670d931 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/caffeine-smi2.tex
+++ b/graphics/mol2chemfig/docs/examples/caffeine-smi2.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/caffeine.mol b/graphics/mol2chemfig/docs/examples/caffeine.mol
index b2d778e47e..b2d778e47e 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/caffeine.mol
+++ b/graphics/mol2chemfig/docs/examples/caffeine.mol
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/caffeine.smi b/graphics/mol2chemfig/docs/examples/caffeine.smi
index fd1cc5f151..fd1cc5f151 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/caffeine.smi
+++ b/graphics/mol2chemfig/docs/examples/caffeine.smi
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/ce-submol1.tex b/graphics/mol2chemfig/docs/examples/ce-submol1.tex
index 361453c98e..361453c98e 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/ce-submol1.tex
+++ b/graphics/mol2chemfig/docs/examples/ce-submol1.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/ce-submol2.tex b/graphics/mol2chemfig/docs/examples/ce-submol2.tex
index fa9d4f44d7..fa9d4f44d7 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/ce-submol2.tex
+++ b/graphics/mol2chemfig/docs/examples/ce-submol2.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/ce-submol3.tex b/graphics/mol2chemfig/docs/examples/ce-submol3.tex
index 1821d496c5..1821d496c5 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/ce-submol3.tex
+++ b/graphics/mol2chemfig/docs/examples/ce-submol3.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/crown-ether.mol b/graphics/mol2chemfig/docs/examples/crown-ether.mol
index f7cf5a32e8..f7cf5a32e8 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/crown-ether.mol
+++ b/graphics/mol2chemfig/docs/examples/crown-ether.mol
diff --git a/graphics/mol2chemfig/docs/examples/cubane-cross-n.sh b/graphics/mol2chemfig/docs/examples/cubane-cross-n.sh
new file mode 100755
index 0000000000..02902da4ac
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/cubane-cross-n.sh
@@ -0,0 +1 @@
+mol2chemfig -t 2 -wn -k 2-5,4-7 cubane.mol > eschers-cubane.tex \ No newline at end of file
diff --git a/graphics/mol2chemfig/docs/examples/cubane-cross.sh b/graphics/mol2chemfig/docs/examples/cubane-cross.sh
new file mode 100755
index 0000000000..6f6d8671ce
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/cubane-cross.sh
@@ -0,0 +1 @@
+mol2chemfig -t 2 -w -k 2-5,4-7 cubane.mol > cubane-cross.tex \ No newline at end of file
diff --git a/graphics/mol2chemfig/docs/examples/cubane-n.sh b/graphics/mol2chemfig/docs/examples/cubane-n.sh
new file mode 100755
index 0000000000..1756709010
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/cubane-n.sh
@@ -0,0 +1 @@
+mol2chemfig -t 2 -wn cubane.mol > cubane-n.tex \ No newline at end of file
diff --git a/graphics/mol2chemfig/docs/examples/cubane-n.tex b/graphics/mol2chemfig/docs/examples/cubane-n.tex
new file mode 100644
index 0000000000..a63dadb9b1
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/cubane-n.tex
@@ -0,0 +1,25 @@
+\chemfig{
+ \mcfatomno{1}% 1
+ -[:90,2]\mcfatomno{2}% 2
+ -[,2]\mcfatomno{5}% 5
+ -[:270,2]\mcfatomno{3}% 3
+ (
+ -[:180,2]\phantom{1}% -> 1
+ )
+ -[:45,1.131]\mcfatomno{7}% 7
+ -[:180,2]\mcfatomno{4}% 4
+ (
+ -[:225,1.131]\phantom{1}% -> 1
+ )
+ -[:90,2]\mcfatomno{6}% 6
+ (
+ -[:225,1.131]\phantom{2}% -> 2
+ )
+ -[,2]\mcfatomno{8}% 8
+ (
+ -[:225,1.131]\phantom{5}% -> 5
+ )
+ (
+ -[:270,2]\phantom{7}% -> 7
+ )
+}
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/cubane.mol b/graphics/mol2chemfig/docs/examples/cubane.mol
index cd329e0eff..cd329e0eff 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/cubane.mol
+++ b/graphics/mol2chemfig/docs/examples/cubane.mol
diff --git a/graphics/mol2chemfig/docs/examples/cubane.sdf b/graphics/mol2chemfig/docs/examples/cubane.sdf
new file mode 100644
index 0000000000..17032e80c8
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/cubane.sdf
@@ -0,0 +1,140 @@
+136090
+ -OEChem-01111309252D
+
+ 16 20 0 0 0 0 0 0 0999 V2000
+ 2.0000 -0.7000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.0000 0.3000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.0000 -0.7000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.4000 -0.3000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.0000 0.3000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.4000 0.7000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.4000 -0.3000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.4000 0.7000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 1.5616 -1.1384 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 1.4272 0.5373 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.2373 -1.2728 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.6373 -0.8728 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.7627 0.8728 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.1627 1.2728 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.9728 -0.5373 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.8384 1.1384 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 2 1 0 0 0 0
+ 1 3 1 0 0 0 0
+ 1 4 1 0 0 0 0
+ 1 9 1 0 0 0 0
+ 2 5 1 0 0 0 0
+ 2 6 1 0 0 0 0
+ 2 10 1 0 0 0 0
+ 3 5 1 0 0 0 0
+ 3 7 1 0 0 0 0
+ 3 11 1 0 0 0 0
+ 4 6 1 0 0 0 0
+ 4 7 1 0 0 0 0
+ 4 12 1 0 0 0 0
+ 5 8 1 0 0 0 0
+ 5 13 1 0 0 0 0
+ 6 8 1 0 0 0 0
+ 6 14 1 0 0 0 0
+ 7 8 1 0 0 0 0
+ 7 15 1 0 0 0 0
+ 8 16 1 0 0 0 0
+M END
+> <PUBCHEM_COMPOUND_CID>
+136090
+
+> <PUBCHEM_COMPOUND_CANONICALIZED>
+1
+
+> <PUBCHEM_CACTVS_COMPLEXITY>
+110
+
+> <PUBCHEM_CACTVS_HBOND_ACCEPTOR>
+0
+
+> <PUBCHEM_CACTVS_HBOND_DONOR>
+0
+
+> <PUBCHEM_CACTVS_ROTATABLE_BOND>
+0
+
+> <PUBCHEM_CACTVS_SUBSKEYS>
+AAADccBwAAAAAAAAAAAAAAAAAABgwAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAADQCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAEAgIAOgAAAAAAAAACAAAAAACAAAAAAAAAAAA==
+
+> <PUBCHEM_IUPAC_OPENEYE_NAME>
+cubane
+
+> <PUBCHEM_IUPAC_CAS_NAME>
+cubane
+
+> <PUBCHEM_IUPAC_NAME>
+cubane
+
+> <PUBCHEM_IUPAC_SYSTEMATIC_NAME>
+cubane
+
+> <PUBCHEM_IUPAC_TRADITIONAL_NAME>
+cubane
+
+> <PUBCHEM_IUPAC_INCHI>
+InChI=1S/C8H8/c1-2-5-3(1)7-4(1)6(2)8(5)7/h1-8H
+
+> <PUBCHEM_IUPAC_INCHIKEY>
+TXWRERCHRDBNLG-UHFFFAOYSA-N
+
+> <PUBCHEM_XLOGP3_AA>
+1.2
+
+> <PUBCHEM_EXACT_MASS>
+104.0626
+
+> <PUBCHEM_MOLECULAR_FORMULA>
+C8H8
+
+> <PUBCHEM_MOLECULAR_WEIGHT>
+104.14912
+
+> <PUBCHEM_OPENEYE_CAN_SMILES>
+C12C3C4C1C5C2C3C45
+
+> <PUBCHEM_OPENEYE_ISO_SMILES>
+C12C3C4C1C5C2C3C45
+
+> <PUBCHEM_CACTVS_TPSA>
+0
+
+> <PUBCHEM_MONOISOTOPIC_WEIGHT>
+104.0626
+
+> <PUBCHEM_TOTAL_CHARGE>
+0
+
+> <PUBCHEM_HEAVY_ATOM_COUNT>
+8
+
+> <PUBCHEM_ATOM_DEF_STEREO_COUNT>
+0
+
+> <PUBCHEM_ATOM_UDEF_STEREO_COUNT>
+0
+
+> <PUBCHEM_BOND_DEF_STEREO_COUNT>
+0
+
+> <PUBCHEM_BOND_UDEF_STEREO_COUNT>
+0
+
+> <PUBCHEM_ISOTOPIC_ATOM_COUNT>
+0
+
+> <PUBCHEM_COMPONENT_COUNT>
+1
+
+> <PUBCHEM_CACTVS_TAUTO_COUNT>
+1
+
+> <PUBCHEM_COORDINATE_TYPE>
+1
+5
+255
+
+$$$$
diff --git a/graphics/mol2chemfig/docs/examples/cubane.sh b/graphics/mol2chemfig/docs/examples/cubane.sh
new file mode 100755
index 0000000000..fc2973d3a5
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/cubane.sh
@@ -0,0 +1 @@
+mol2chemfig -t 2 -w cubane.mol > cubane.tex \ No newline at end of file
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/daptomycin-u.sh b/graphics/mol2chemfig/docs/examples/daptomycin-u.sh
index bd26c321ea..bd26c321ea 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/daptomycin-u.sh
+++ b/graphics/mol2chemfig/docs/examples/daptomycin-u.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/daptomycin-u.tex b/graphics/mol2chemfig/docs/examples/daptomycin-u.tex
index 7bd845b685..7bd845b685 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/daptomycin-u.tex
+++ b/graphics/mol2chemfig/docs/examples/daptomycin-u.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/daptomycin.mol b/graphics/mol2chemfig/docs/examples/daptomycin.mol
index 7db489f00b..7db489f00b 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/daptomycin.mol
+++ b/graphics/mol2chemfig/docs/examples/daptomycin.mol
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/daptomycin.tex b/graphics/mol2chemfig/docs/examples/daptomycin.tex
index 2ccf1e736f..2ccf1e736f 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/daptomycin.tex
+++ b/graphics/mol2chemfig/docs/examples/daptomycin.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/daptomycin1.sh b/graphics/mol2chemfig/docs/examples/daptomycin1.sh
index 12314a3aec..12314a3aec 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/daptomycin1.sh
+++ b/graphics/mol2chemfig/docs/examples/daptomycin1.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/dcf-submol1.tex b/graphics/mol2chemfig/docs/examples/dcf-submol1.tex
index 3787320606..3787320606 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/dcf-submol1.tex
+++ b/graphics/mol2chemfig/docs/examples/dcf-submol1.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/dcf-submol2.tex b/graphics/mol2chemfig/docs/examples/dcf-submol2.tex
index e7a95777fe..e7a95777fe 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/dcf-submol2.tex
+++ b/graphics/mol2chemfig/docs/examples/dcf-submol2.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/dcf-submol3.tex b/graphics/mol2chemfig/docs/examples/dcf-submol3.tex
index 33413d9eb5..33413d9eb5 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/dcf-submol3.tex
+++ b/graphics/mol2chemfig/docs/examples/dcf-submol3.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/dichlorofluorescein.mol b/graphics/mol2chemfig/docs/examples/dichlorofluorescein.mol
index 620c1683c8..620c1683c8 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/dichlorofluorescein.mol
+++ b/graphics/mol2chemfig/docs/examples/dichlorofluorescein.mol
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/dichlorofluorescein1.sh b/graphics/mol2chemfig/docs/examples/dichlorofluorescein1.sh
index 51d2b28545..51d2b28545 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/dichlorofluorescein1.sh
+++ b/graphics/mol2chemfig/docs/examples/dichlorofluorescein1.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/dichlorofluorescein2.sh b/graphics/mol2chemfig/docs/examples/dichlorofluorescein2.sh
index ef10d00ea3..ef10d00ea3 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/dichlorofluorescein2.sh
+++ b/graphics/mol2chemfig/docs/examples/dichlorofluorescein2.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/dichlorofluorescein3.sh b/graphics/mol2chemfig/docs/examples/dichlorofluorescein3.sh
index 2d7c788b20..2d7c788b20 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/dichlorofluorescein3.sh
+++ b/graphics/mol2chemfig/docs/examples/dichlorofluorescein3.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/doxo-from-sdf.sh b/graphics/mol2chemfig/docs/examples/doxo-from-sdf.sh
index b948344b9a..b948344b9a 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/doxo-from-sdf.sh
+++ b/graphics/mol2chemfig/docs/examples/doxo-from-sdf.sh
diff --git a/graphics/mol2chemfig/docs/examples/doxo-hand-rotated.sh b/graphics/mol2chemfig/docs/examples/doxo-hand-rotated.sh
new file mode 100755
index 0000000000..ea509cfd42
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/doxo-hand-rotated.sh
@@ -0,0 +1 @@
+mol2chemfig -a 20 -u -w -y delete doxorubicin.sdf > doxo-hand-rotated.tex \ No newline at end of file
diff --git a/graphics/mol2chemfig/docs/examples/doxo-numbered.sh b/graphics/mol2chemfig/docs/examples/doxo-numbered.sh
new file mode 100755
index 0000000000..72af2b46be
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/doxo-numbered.sh
@@ -0,0 +1 @@
+mol2chemfig -n -w -y delete doxorubicin.sdf > doxo-numbered.tex \ No newline at end of file
diff --git a/graphics/mol2chemfig/docs/examples/doxo-numbered.tex b/graphics/mol2chemfig/docs/examples/doxo-numbered.tex
new file mode 100644
index 0000000000..80fcfdd637
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/doxo-numbered.tex
@@ -0,0 +1,74 @@
+\chemfig{
+ \mcfleft{\mcfatomno{3}}{O}% 3
+ >:[:60.2]\mcfatomno{14}% 14
+ (
+ -[:180.2]\mcfatomno{25}% 25
+ (
+ -[:240.2]\mcfatomno{30}% 30
+ -[:180.2]\mcfleft{\mcfatomno{8}}{O}% 8
+ )
+ =[:120.2]\mcfleft{\mcfatomno{7}}{O}% 7
+ )
+ -[:90,1.042]\mcfatomno{15}% 15
+ -[:29.6,1.042]\mcfatomno{13}% 13
+ (
+ <:[:89.3]\mcfright{O}{\mcfatomno{1}}% 1
+ >:[:149.3]\mcfatomno{19}% 19
+ -[:209.3]\mcfbelow{O}{\mcfatomno{2}}% 2
+ -[:149.3]\mcfatomno{23}% 23
+ (
+ <[:209.3]\mcfatomno{29}% 29
+ )
+ -[:89.3]\mcfatomno{22}% 22
+ (
+ -[:29.3]\mcfatomno{21}% 21
+ (
+ -[:329.3]\mcfatomno{20}% 20
+ -[:269.3]\phantom{19}% -> 19
+ )
+ <[:89.3]\mcfright{N}{\mcfatomno{12}}% 12
+ )
+ <[:149.3]\mcfleft{\mcfatomno{4}}{O}% 4
+ )
+ -[:329.1,1.042]\mcfatomno{17}% 17
+ -[:270]\mcfatomno{18}% 18
+ (
+ -[:210.9,1.042]\mcfatomno{16}% 16
+ -[:150.4,1.042]\phantom{14}% -> 14
+ )
+ =^[:330]\mcfatomno{26}% 26
+ (
+ -[:270]\mcfright{O}{\mcfatomno{6}}% 6
+ )
+ -[:30]\mcfatomno{28}% 28
+ =^[:90]\mcfatomno{27}% 27
+ (
+ -[:150]\mcfatomno{24}% 24
+ (
+ =^[:210]\phantom{17}% -> 17
+ )
+ -[:90]\mcfright{O}{\mcfatomno{5}}% 5
+ )
+ -[:30.9,1.042]\mcfatomno{31}% 31
+ (
+ =[:90.7]\mcfright{O}{\mcfatomno{9}}% 9
+ )
+ -[:330.4,1.042]\mcfatomno{33}% 33
+ =^[:270,1.042]\mcfatomno{34}% 34
+ (
+ -[:209.6,1.042]\mcfatomno{32}% 32
+ (
+ -[:149.1,1.042]\phantom{28}% -> 28
+ )
+ =[:269.3]\mcfright{O}{\mcfatomno{10}}% 10
+ )
+ -[:329.1,1.085]\mcfatomno{36}% 36
+ =^[:29.6,1.085]\mcfatomno{38}% 38
+ -[:90,1.085]\mcfatomno{37}% 37
+ =^[:150.4,1.085]\mcfatomno{35}% 35
+ (
+ -[:210.9,1.085]\phantom{33}% -> 33
+ )
+ -[:90.7]\mcfleft{\mcfatomno{11}}{O}% 11
+ -[:30.7]\mcfatomno{39}% 39
+}
diff --git a/graphics/mol2chemfig/docs/examples/doxo-ratcheted-rotated.sh b/graphics/mol2chemfig/docs/examples/doxo-ratcheted-rotated.sh
new file mode 100755
index 0000000000..4bad92b51f
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/doxo-ratcheted-rotated.sh
@@ -0,0 +1 @@
+mol2chemfig -r 30 -a 180 -u -w -y delete doxorubicin.sdf > doxo-rat-rot.tex \ No newline at end of file
diff --git a/graphics/mol2chemfig/docs/examples/doxo-ratcheted.sh b/graphics/mol2chemfig/docs/examples/doxo-ratcheted.sh
new file mode 100755
index 0000000000..07810a9a01
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/doxo-ratcheted.sh
@@ -0,0 +1 @@
+mol2chemfig -r 30 -u -w -y delete doxorubicin.sdf > doxo-ratcheted.tex \ No newline at end of file
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/doxo-raw.tex b/graphics/mol2chemfig/docs/examples/doxo-raw.tex
index 1af8856904..1af8856904 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/doxo-raw.tex
+++ b/graphics/mol2chemfig/docs/examples/doxo-raw.tex
diff --git a/graphics/mol2chemfig/docs/examples/doxo-recalculated-flopped.sh b/graphics/mol2chemfig/docs/examples/doxo-recalculated-flopped.sh
new file mode 100755
index 0000000000..9f03e17faf
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/doxo-recalculated-flopped.sh
@@ -0,0 +1 @@
+mol2chemfig -qwu -y delete doxorubicin.sdf > doxo-recalculated-flopped.tex \ No newline at end of file
diff --git a/graphics/mol2chemfig/docs/examples/doxo-recalculated-flopped.tex b/graphics/mol2chemfig/docs/examples/doxo-recalculated-flopped.tex
new file mode 100644
index 0000000000..7b3407a792
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/doxo-recalculated-flopped.tex
@@ -0,0 +1,74 @@
+\chemfig{
+ HO% 3
+ >[:290,,2]% 14
+ (
+ -[:190]% 25
+ (
+ -[:130]% 30
+ -[:190,,,2]HO% 8
+ )
+ =[:250]O% 7
+ )
+ -[:270]% 15
+ -[:330]% 13
+ (
+ <[:270]O% 1
+ >:[:210]% 19
+ -[:270]O% 2
+ -[:210]% 23
+ (
+ <[:270]% 29
+ )
+ -[:150]% 22
+ (
+ -[:90]% 21
+ (
+ -[:30]% 20
+ -[:330]% -> 19
+ )
+ <[:150,,,2]H_2N% 12
+ )
+ <[:210,,,2]HO% 4
+ )
+ -[:30]% 17
+ -[:90]% 18
+ (
+ -[:150]% 16
+ -[:210]% -> 14
+ )
+ =_[:30]% 26
+ (
+ -[:90,,,1]OH% 6
+ )
+ -[:330]% 28
+ =_[:270]% 27
+ (
+ -[:210]% 24
+ (
+ =_[:150]% -> 17
+ )
+ -[:270,,,1]OH% 5
+ )
+ -[:330]% 31
+ (
+ =[:270]O% 9
+ )
+ -[:30]% 33
+ =_[:90]% 34
+ (
+ -[:150]% 32
+ (
+ -[:210]% -> 28
+ )
+ =[:90]O% 10
+ )
+ -[:30]% 36
+ =_[:330]% 38
+ -[:270]% 37
+ =_[:210]% 35
+ (
+ -[:150]% -> 33
+ )
+ -[:270]O% 11
+ -[:330]% 39
+}
diff --git a/graphics/mol2chemfig/docs/examples/doxo-recalculated-rotated.sh b/graphics/mol2chemfig/docs/examples/doxo-recalculated-rotated.sh
new file mode 100755
index 0000000000..22c0a8ffdd
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/doxo-recalculated-rotated.sh
@@ -0,0 +1 @@
+mol2chemfig -wu -y delete -a 30 doxorubicin.sdf > doxo-recalculated-rotated.tex \ No newline at end of file
diff --git a/graphics/mol2chemfig/docs/examples/doxo-recalculated-rotated.tex b/graphics/mol2chemfig/docs/examples/doxo-recalculated-rotated.tex
new file mode 100644
index 0000000000..4be5361799
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/doxo-recalculated-rotated.tex
@@ -0,0 +1,74 @@
+\chemfig{
+ OH% 3
+ >:[:100,,1]% 14
+ (
+ -[:200]% 25
+ (
+ -[:260]% 30
+ -[:200,,,2]HO% 8
+ )
+ =[:140]O% 7
+ )
+ -[:120]% 15
+ -[:60]% 13
+ (
+ <:[:120]O% 1
+ >[:180]% 19
+ -[:120]O% 2
+ -[:180]% 23
+ (
+ <:[:120]% 29
+ )
+ -[:240]% 22
+ (
+ -[:300]% 21
+ (
+ -% 20
+ -[:60]% -> 19
+ )
+ <:[:240,,,2]H_2N% 12
+ )
+ <:[:180,,,2]HO% 4
+ )
+ -% 17
+ -[:300]% 18
+ (
+ -[:240]% 16
+ -[:180]% -> 14
+ )
+ =^% 26
+ (
+ -[:300,,,1]OH% 6
+ )
+ -[:60]% 28
+ =^[:120]% 27
+ (
+ -[:180]% 24
+ (
+ =^[:240]% -> 17
+ )
+ -[:120,,,2]HO% 5
+ )
+ -[:60]% 31
+ (
+ =[:120]O% 9
+ )
+ -% 33
+ =^[:300]% 34
+ (
+ -[:240]% 32
+ (
+ -[:180]% -> 28
+ )
+ =[:300]O% 10
+ )
+ -% 36
+ =^[:60]% 38
+ -[:120]% 37
+ =^[:180]% 35
+ (
+ -[:240]% -> 33
+ )
+ -[:120]O% 11
+ -[:60]% 39
+}
diff --git a/graphics/mol2chemfig/docs/examples/doxo-recalculated.sh b/graphics/mol2chemfig/docs/examples/doxo-recalculated.sh
new file mode 100755
index 0000000000..de4e694226
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/doxo-recalculated.sh
@@ -0,0 +1 @@
+mol2chemfig -u -w -y delete doxorubicin.sdf > doxo-recalculated.tex \ No newline at end of file
diff --git a/graphics/mol2chemfig/docs/examples/doxo-recalculated.tex b/graphics/mol2chemfig/docs/examples/doxo-recalculated.tex
new file mode 100644
index 0000000000..a4029d35c1
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/doxo-recalculated.tex
@@ -0,0 +1,74 @@
+\chemfig{
+ HO% 3
+ >:[:70,,2]% 14
+ (
+ -[:170]% 25
+ (
+ -[:230]% 30
+ -[:170,,,2]HO% 8
+ )
+ =[:110]O% 7
+ )
+ -[:90]% 15
+ -[:30]% 13
+ (
+ <:[:90]O% 1
+ >[:150]% 19
+ -[:90]O% 2
+ -[:150]% 23
+ (
+ <:[:90]% 29
+ )
+ -[:210]% 22
+ (
+ -[:270]% 21
+ (
+ -[:330]% 20
+ -[:30]% -> 19
+ )
+ <:[:210,,,2]H_2N% 12
+ )
+ <:[:150,,,2]HO% 4
+ )
+ -[:330]% 17
+ -[:270]% 18
+ (
+ -[:210]% 16
+ -[:150]% -> 14
+ )
+ =^[:330]% 26
+ (
+ -[:270,,,1]OH% 6
+ )
+ -[:30]% 28
+ =^[:90]% 27
+ (
+ -[:150]% 24
+ (
+ =^[:210]% -> 17
+ )
+ -[:90,,,1]OH% 5
+ )
+ -[:30]% 31
+ (
+ =[:90]O% 9
+ )
+ -[:330]% 33
+ =^[:270]% 34
+ (
+ -[:210]% 32
+ (
+ -[:150]% -> 28
+ )
+ =[:270]O% 10
+ )
+ -[:330]% 36
+ =^[:30]% 38
+ -[:90]% 37
+ =^[:150]% 35
+ (
+ -[:210]% -> 33
+ )
+ -[:90]O% 11
+ -[:30]% 39
+}
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/doxo-strip-h.sh b/graphics/mol2chemfig/docs/examples/doxo-strip-h.sh
index 411ecf8d89..411ecf8d89 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/doxo-strip-h.sh
+++ b/graphics/mol2chemfig/docs/examples/doxo-strip-h.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/doxo-stripped.tex b/graphics/mol2chemfig/docs/examples/doxo-stripped.tex
index c177de0873..c177de0873 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/doxo-stripped.tex
+++ b/graphics/mol2chemfig/docs/examples/doxo-stripped.tex
diff --git a/graphics/mol2chemfig/docs/examples/doxorubicin.sdf b/graphics/mol2chemfig/docs/examples/doxorubicin.sdf
new file mode 100644
index 0000000000..01b7ceeaa2
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/doxorubicin.sdf
@@ -0,0 +1,264 @@
+31703
+ -OEChem-05091217182D
+
+ 68 72 0 1 0 0 0 0 0999 V2000
+ 5.9812 0.5043 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 4.2493 0.5243 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 4.5669 -2.9191 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.5405 2.5442 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 7.7296 0.4697 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 7.7296 -3.5303 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.5603 -1.1909 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.5670 -2.9268 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 9.4780 0.5043 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 9.4780 -3.5649 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 11.3153 0.5474 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 4.2840 3.5241 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
+ 5.9697 -0.4956 0.0000 C 0 0 1 0 0 0 0 0 0 0 0 0
+ 5.0636 -2.0511 0.0000 C 0 0 2 0 0 0 0 0 0 0 0 0
+ 5.0636 -1.0095 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 5.9697 -2.5650 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 6.8636 -1.0303 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 6.8636 -2.0303 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 5.1210 1.0143 0.0000 C 0 0 2 0 0 0 0 0 0 0 0 0
+ 5.1326 2.0142 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 4.2724 2.5242 0.0000 C 0 0 1 0 0 0 0 0 0 0 0 0
+ 3.4007 2.0342 0.0000 C 0 0 1 0 0 0 0 0 0 0 0 0
+ 3.3891 1.0343 0.0000 C 0 0 2 0 0 0 0 0 0 0 0 0
+ 7.7296 -0.5303 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 4.0636 -2.0550 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 7.7296 -2.5303 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 8.5957 -1.0303 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 8.5957 -2.0303 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.5174 0.5443 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.5670 -2.9229 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 9.4896 -0.4956 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 9.4896 -2.5650 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 10.3957 -1.0095 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 10.3957 -2.0511 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 11.3268 -0.4526 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 11.3268 -2.6080 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 12.2706 -0.9878 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 12.2706 -2.0728 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 12.1754 1.0573 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 5.4357 -0.1805 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 4.8545 -0.4258 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 4.4527 -1.1156 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 5.5760 -3.0440 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 6.3743 -3.0348 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 5.6615 1.3180 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 5.7419 1.8995 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 5.3514 2.5943 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.7391 2.8404 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.8602 1.7305 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.3819 0.4143 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 4.8790 -3.4548 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.2136 1.0848 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 1.9769 0.2406 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.8211 0.0039 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 4.8245 3.8279 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.7507 3.8403 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.4616 -3.5339 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 4.1504 -3.1327 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.0000 2.2404 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 8.2666 0.7797 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 7.1927 -3.8403 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 11.3197 -3.2280 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.2590 -3.4649 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 12.8063 -0.6757 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 12.8063 -2.3849 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 12.4916 0.5240 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 12.7088 1.3735 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 11.8593 1.5907 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
+ 13 1 1 6 0 0 0
+ 19 1 1 6 0 0 0
+ 2 19 1 0 0 0 0
+ 2 23 1 0 0 0 0
+ 14 3 1 6 0 0 0
+ 3 51 1 0 0 0 0
+ 22 4 1 1 0 0 0
+ 4 59 1 0 0 0 0
+ 5 24 1 0 0 0 0
+ 5 60 1 0 0 0 0
+ 6 26 1 0 0 0 0
+ 6 61 1 0 0 0 0
+ 7 25 2 0 0 0 0
+ 8 30 1 0 0 0 0
+ 8 63 1 0 0 0 0
+ 9 31 2 0 0 0 0
+ 10 32 2 0 0 0 0
+ 11 35 1 0 0 0 0
+ 11 39 1 0 0 0 0
+ 21 12 1 1 0 0 0
+ 12 55 1 0 0 0 0
+ 12 56 1 0 0 0 0
+ 13 15 1 0 0 0 0
+ 13 17 1 0 0 0 0
+ 13 40 1 0 0 0 0
+ 14 15 1 0 0 0 0
+ 14 16 1 0 0 0 0
+ 14 25 1 0 0 0 0
+ 15 41 1 0 0 0 0
+ 15 42 1 0 0 0 0
+ 16 18 1 0 0 0 0
+ 16 43 1 0 0 0 0
+ 16 44 1 0 0 0 0
+ 17 18 1 0 0 0 0
+ 17 24 2 0 0 0 0
+ 18 26 2 0 0 0 0
+ 19 20 1 0 0 0 0
+ 19 45 1 0 0 0 0
+ 20 21 1 0 0 0 0
+ 20 46 1 0 0 0 0
+ 20 47 1 0 0 0 0
+ 21 22 1 0 0 0 0
+ 21 48 1 0 0 0 0
+ 22 23 1 0 0 0 0
+ 22 49 1 0 0 0 0
+ 23 29 1 1 0 0 0
+ 23 50 1 0 0 0 0
+ 24 27 1 0 0 0 0
+ 25 30 1 0 0 0 0
+ 26 28 1 0 0 0 0
+ 27 28 2 0 0 0 0
+ 27 31 1 0 0 0 0
+ 28 32 1 0 0 0 0
+ 29 52 1 0 0 0 0
+ 29 53 1 0 0 0 0
+ 29 54 1 0 0 0 0
+ 30 57 1 0 0 0 0
+ 30 58 1 0 0 0 0
+ 31 33 1 0 0 0 0
+ 32 34 1 0 0 0 0
+ 33 34 2 0 0 0 0
+ 33 35 1 0 0 0 0
+ 34 36 1 0 0 0 0
+ 35 37 2 0 0 0 0
+ 36 38 2 0 0 0 0
+ 36 62 1 0 0 0 0
+ 37 38 1 0 0 0 0
+ 37 64 1 0 0 0 0
+ 38 65 1 0 0 0 0
+ 39 66 1 0 0 0 0
+ 39 67 1 0 0 0 0
+ 39 68 1 0 0 0 0
+M END
+> <PUBCHEM_COMPOUND_CID>
+31703
+
+> <PUBCHEM_COMPOUND_CANONICALIZED>
+1
+
+> <PUBCHEM_MOLECULAR_WEIGHT>
+543.51926
+
+> <PUBCHEM_MONOISOTOPIC_WEIGHT>
+543.174061
+
+> <PUBCHEM_EXACT_MASS>
+543.174061
+
+> <PUBCHEM_MOLECULAR_FORMULA>
+C27H29NO11
+
+> <PUBCHEM_IUPAC_INCHI>
+InChI=1S/C27H29NO11/c1-10-22(31)13(28)6-17(38-10)39-15-8-27(36,16(30)9-29)7-12-19(15)26(35)21-20(24(12)33)23(32)11-4-3-5-14(37-2)18(11)25(21)34/h3-5,10,13,15,17,22,29,31,33,35-36H,6-9,28H2,1-2H3/t10-,13-,15-,17-,22+,27-/m0/s1
+
+> <PUBCHEM_IUPAC_INCHIKEY>
+AOJJSUZBOXZQNB-TZSSRYMLSA-N
+
+> <PUBCHEM_XLOGP3>
+1.3
+
+> <PUBCHEM_OPENEYE_CAN_SMILES>
+CC1C(C(CC(O1)OC2CC(CC3=C(C4=C(C(=C23)O)C(=O)C5=C(C4=O)C=CC=C5OC)O)(C(=O)CO)O)N)O
+
+> <PUBCHEM_OPENEYE_ISO_SMILES>
+C[C@H]1[C@H]([C@H](C[C@@H](O1)O[C@H]2C[C@@](CC3=C(C4=C(C(=C23)O)C(=O)C5=C(C4=O)C=CC=C5OC)O)(C(=O)CO)O)N)O
+
+> <PUBCHEM_IUPAC_NAME>
+(7S,9S)-7-[(2R,4S,5S,6S)-4-amino-5-hydroxy-6-methyloxan-2-yl]oxy-6,9,11-trihydroxy-9-(2-hydroxyacetyl)-4-methoxy-8,10-dihydro-7H-tetracene-5,12-dione
+
+> <PUBCHEM_IUPAC_OPENEYE_NAME>
+(7S,9S)-7-[(2R,4S,5S,6S)-4-amino-5-hydroxy-6-methyl-tetrahydropyran-2-yl]oxy-6,9,11-trihydroxy-9-(2-hydroxyacetyl)-4-methoxy-8,10-dihydro-7H-tetracene-5,12-dione
+
+> <PUBCHEM_IUPAC_CAS_NAME>
+(7S,9S)-7-[[(2R,4S,5S,6S)-4-amino-5-hydroxy-6-methyl-2-oxanyl]oxy]-6,9,11-trihydroxy-9-(2-hydroxy-1-oxoethyl)-4-methoxy-8,10-dihydro-7H-tetracene-5,12-dione
+
+> <PUBCHEM_IUPAC_TRADITIONAL_NAME>
+(7S,9S)-7-[(2R,4S,5S,6S)-4-amino-5-hydroxy-6-methyl-tetrahydropyran-2-yl]oxy-9-glycoloyl-6,9,11-trihydroxy-4-methoxy-8,10-dihydro-7H-tetracene-5,12-quinone
+
+> <PUBCHEM_IUPAC_SYSTEMATIC_NAME>
+(7S,9S)-7-[(2R,4S,5S,6S)-4-azanyl-6-methyl-5-oxidanyl-oxan-2-yl]oxy-4-methoxy-6,9,11-tris(oxidanyl)-9-(2-oxidanylethanoyl)-8,10-dihydro-7H-tetracene-5,12-dione
+
+> <PUBCHEM_CACTVS_HBOND_DONOR>
+6
+
+> <PUBCHEM_CACTVS_HBOND_ACCEPTOR>
+12
+
+> <PUBCHEM_CACTVS_ROTATABLE_BOND>
+5
+
+> <PUBCHEM_CACTVS_COMPLEXITY>
+977
+
+> <PUBCHEM_CACTVS_TPSA>
+206
+
+> <PUBCHEM_CACTVS_SUBSKEYS>
+AAADceB6PAAAAAAAAAAAAAAAAAAAAAAAAAA0YMGCAAAAAADBQAAAHgAQCAAADHzxmAcyDoBABgCIAqBSAAICCAAkIAAIiIFGCMgfNzaGtRqicWAn8BEPuYfL7PzOwQADAAAYAADCAAYQADAAAAAAAAAAAA==
+
+> <PUBCHEM_TOTAL_CHARGE>
+0
+
+> <PUBCHEM_HEAVY_ATOM_COUNT>
+39
+
+> <PUBCHEM_ATOM_DEF_STEREO_COUNT>
+6
+
+> <PUBCHEM_ATOM_UDEF_STEREO_COUNT>
+0
+
+> <PUBCHEM_BOND_DEF_STEREO_COUNT>
+0
+
+> <PUBCHEM_BOND_UDEF_STEREO_COUNT>
+0
+
+> <PUBCHEM_ISOTOPIC_ATOM_COUNT>
+0
+
+> <PUBCHEM_COMPONENT_COUNT>
+1
+
+> <PUBCHEM_CACTVS_TAUTO_COUNT>
+81
+
+> <PUBCHEM_COORDINATE_TYPE>
+1
+3
+
+> <PUBCHEM_BONDANNOTATIONS>
+13 1 6
+19 1 6
+21 12 5
+17 18 8
+17 24 8
+18 26 8
+23 29 5
+24 27 8
+26 28 8
+27 28 8
+14 3 6
+33 34 8
+33 35 8
+34 36 8
+35 37 8
+36 38 8
+37 38 8
+22 4 5
+
+$$$$
+
diff --git a/graphics/mol2chemfig/docs/examples/eschers-cubane.tex b/graphics/mol2chemfig/docs/examples/eschers-cubane.tex
new file mode 100644
index 0000000000..cd7711eb5c
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/eschers-cubane.tex
@@ -0,0 +1,33 @@
+\chemfig{
+ \mcfatomno{1}% 1
+ -[:90,2]\mcfatomno{2}% 2
+ -[,2,,,draw=none]\mcfatomno{5}% 5
+ -[:270,2]\mcfatomno{3}% 3
+ (
+ -[:180,2]\phantom{1}% -> 1
+ )
+ -[:45,1.131]\mcfatomno{7}% 7
+ -[:180,2,,,draw=none]\mcfatomno{4}% 4
+ (
+ -[:225,1.131]\phantom{1}% -> 1
+ )
+ -[:90,2]\mcfatomno{6}% 6
+ (
+ -[:225,1.131]\phantom{2}% -> 2
+ )
+ -[,2]\mcfatomno{8}% 8
+ (
+ -[:225,1.131]\phantom{5}% -> 5
+ )
+ (
+ -[:270,2]\phantom{7}% -> 7
+ )
+ (
+ -[:195.9,2.912,,,draw=none]\phantom{2}% -> 2
+ -[,2,,,mcfx={100}{10}]\phantom{5}% -> 5
+ )
+ (
+ -[:270,2,,,draw=none]\phantom{7}% -> 7
+ -[:180,2,,,mcfx={100}{10}]\phantom{4}% -> 4
+ )
+}
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/fmnh.mol b/graphics/mol2chemfig/docs/examples/fmnh.mol
index 048bc84d05..048bc84d05 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/fmnh.mol
+++ b/graphics/mol2chemfig/docs/examples/fmnh.mol
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/aspirin.tex b/graphics/mol2chemfig/docs/examples/hand-coded-tex/aspirin.tex
index 576c9d8a43..576c9d8a43 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/aspirin.tex
+++ b/graphics/mol2chemfig/docs/examples/hand-coded-tex/aspirin.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/caffeine.tex b/graphics/mol2chemfig/docs/examples/hand-coded-tex/caffeine.tex
index 8b49661938..8b49661938 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/caffeine.tex
+++ b/graphics/mol2chemfig/docs/examples/hand-coded-tex/caffeine.tex
diff --git a/graphics/mol2chemfig/docs/examples/hand-coded-tex/chemfig-settings.tex b/graphics/mol2chemfig/docs/examples/hand-coded-tex/chemfig-settings.tex
new file mode 100644
index 0000000000..df543546d0
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/hand-coded-tex/chemfig-settings.tex
@@ -0,0 +1,15 @@
+% reduce font size and use sans-serif for atoms
+\renewcommand{\printatom}[1]{%
+\fontsize{8pt}{10pt}\selectfont{\ensuremath{\mathsf{#1}}}}
+
+% reduce bond dimensions to match smaller fonts
+\setchemfig{
+ cram rectangle=false,
+ cram width=2.5pt,
+ cram dash width=0.4pt,
+ cram dash sep=1pt,
+ atom sep=16pt,
+ bond offset=1pt,
+ double bond sep=2pt
+}
+
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/sodium-green.png b/graphics/mol2chemfig/docs/examples/hand-coded-tex/sodium-green.png
index 0d8b8c9275..0d8b8c9275 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/sodium-green.png
+++ b/graphics/mol2chemfig/docs/examples/hand-coded-tex/sodium-green.png
Binary files differ
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/sodium-green1.tex b/graphics/mol2chemfig/docs/examples/hand-coded-tex/sodium-green1.tex
index 84da34dd2c..84da34dd2c 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/sodium-green1.tex
+++ b/graphics/mol2chemfig/docs/examples/hand-coded-tex/sodium-green1.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/sodium-green2.tex b/graphics/mol2chemfig/docs/examples/hand-coded-tex/sodium-green2.tex
index 7cea9f0df7..7cea9f0df7 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/sodium-green2.tex
+++ b/graphics/mol2chemfig/docs/examples/hand-coded-tex/sodium-green2.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/sodium-green3.tex b/graphics/mol2chemfig/docs/examples/hand-coded-tex/sodium-green3.tex
index 501995ab65..501995ab65 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/hand-coded-tex/sodium-green3.tex
+++ b/graphics/mol2chemfig/docs/examples/hand-coded-tex/sodium-green3.tex
diff --git a/graphics/mol2chemfig/docs/examples/hand-coded-tex/stuff.tex b/graphics/mol2chemfig/docs/examples/hand-coded-tex/stuff.tex
new file mode 100644
index 0000000000..c22fbd3373
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/hand-coded-tex/stuff.tex
@@ -0,0 +1,8 @@
+\definesubmol{acetyl}{(=[::60]O)-[::-60]H_3C}
+\definesubmol{benzoate}{*6(-=-=-(-(=[::60]O)-[::-60]OH)=)}%
+
+\chemfig{
+ {\color{red}O} % the oxygen in the middle
+ (-[:210]!{acetyl}) % treat one submol as a branch,
+ -[:-30]!{benzoate}% % the other one as the main chain
+}
diff --git a/graphics/mol2chemfig/docs/examples/hand-coded-tex/twisted-commented.tex b/graphics/mol2chemfig/docs/examples/hand-coded-tex/twisted-commented.tex
new file mode 100644
index 0000000000..dfe0fdb3a7
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/hand-coded-tex/twisted-commented.tex
@@ -0,0 +1,25 @@
+% used options: used options: -w -t 2 (no cross bond)
+\chemfig{
+ % 1
+ -[,1.414]% 2
+ -[:225,2]% 4
+ -[,1.414]% 3
+ (
+ -[:135,2]% -> 1
+ )
+}
+
+% added option: --cross-bond 2-4
+\chemfig{
+ % 1
+ -[,1.414]% 2
+ -[:225,2,,,draw=none]% 4 bond 2 -> 4 is not rendered at first
+ -[,1.414]% 3
+ (
+ -[:135,2]% -> 1
+ )
+ (% append cross bond to end of molecule
+ -[:90,1.414,,,draw=none]% -> 2 - invisible bond moves the pen to atom 2
+ -[:225,2,,,mcfcrossbond]% -> 4 - the cross bond is rendered, applying
+ )% the mcfcrossbond tikz key
+}
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/morphine-f.sh b/graphics/mol2chemfig/docs/examples/morphine-f.sh
index bd4b560de5..bd4b560de5 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/morphine-f.sh
+++ b/graphics/mol2chemfig/docs/examples/morphine-f.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/morphine-f.tex b/graphics/mol2chemfig/docs/examples/morphine-f.tex
index 3557709128..3557709128 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/morphine-f.tex
+++ b/graphics/mol2chemfig/docs/examples/morphine-f.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/morphine-k.sh b/graphics/mol2chemfig/docs/examples/morphine-k.sh
index a280f43747..a280f43747 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/morphine-k.sh
+++ b/graphics/mol2chemfig/docs/examples/morphine-k.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/morphine-k.tex b/graphics/mol2chemfig/docs/examples/morphine-k.tex
index bb75634e18..bb75634e18 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/morphine-k.tex
+++ b/graphics/mol2chemfig/docs/examples/morphine-k.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/morphine-n.sh b/graphics/mol2chemfig/docs/examples/morphine-n.sh
index d2c76db071..d2c76db071 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/morphine-n.sh
+++ b/graphics/mol2chemfig/docs/examples/morphine-n.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/morphine-n.tex b/graphics/mol2chemfig/docs/examples/morphine-n.tex
index 3ad8cc6d48..3ad8cc6d48 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/morphine-n.tex
+++ b/graphics/mol2chemfig/docs/examples/morphine-n.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/morphine.mol b/graphics/mol2chemfig/docs/examples/morphine.mol
index 4d17710747..4d17710747 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/morphine.mol
+++ b/graphics/mol2chemfig/docs/examples/morphine.mol
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/morphine.sh b/graphics/mol2chemfig/docs/examples/morphine.sh
index e0b0319867..e0b0319867 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/morphine.sh
+++ b/graphics/mol2chemfig/docs/examples/morphine.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/morphine.tex b/graphics/mol2chemfig/docs/examples/morphine.tex
index ba80f885ba..ba80f885ba 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/morphine.tex
+++ b/graphics/mol2chemfig/docs/examples/morphine.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/mp.mol b/graphics/mol2chemfig/docs/examples/mp.mol
index 5dcb270ade..5dcb270ade 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/mp.mol
+++ b/graphics/mol2chemfig/docs/examples/mp.mol
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/mp.sh b/graphics/mol2chemfig/docs/examples/mp.sh
index 4e9ab919ec..4e9ab919ec 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/mp.sh
+++ b/graphics/mol2chemfig/docs/examples/mp.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/mp.tex b/graphics/mol2chemfig/docs/examples/mp.tex
index 9b94d693ef..9b94d693ef 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/mp.tex
+++ b/graphics/mol2chemfig/docs/examples/mp.tex
diff --git a/graphics/mol2chemfig/docs/examples/mp06900.pdf b/graphics/mol2chemfig/docs/examples/mp06900.pdf
new file mode 100644
index 0000000000..687989258f
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/mp06900.pdf
Binary files differ
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/optionlist.tex b/graphics/mol2chemfig/docs/examples/optionlist.tex
index 44a957117e..0b0d1b2a3b 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/optionlist.tex
+++ b/graphics/mol2chemfig/docs/examples/optionlist.tex
@@ -1,4 +1,4 @@
-mol2chemfig v. 1.4, by Eric Brefo-Mensah and Michael Palmer
+mol2chemfig v. 1.5, by Eric Brefo-Mensah and Michael Palmer
mol2chemfig generates chemfig code from molfiles. Usage example:
mol2chemfig --angle=45 --aromatic-circles somefile.mol
diff --git a/graphics/mol2chemfig/docs/examples/packmoles.sh b/graphics/mol2chemfig/docs/examples/packmoles.sh
new file mode 100755
index 0000000000..6aee669191
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/packmoles.sh
@@ -0,0 +1 @@
+zip example-mol.zip *.mol *.smi *.sdf
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/phenol-add-h.sh b/graphics/mol2chemfig/docs/examples/phenol-add-h.sh
index 5701daf90e..5701daf90e 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/phenol-add-h.sh
+++ b/graphics/mol2chemfig/docs/examples/phenol-add-h.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/phenol-as-submol.sh b/graphics/mol2chemfig/docs/examples/phenol-as-submol.sh
index 59f11e2cf2..59f11e2cf2 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/phenol-as-submol.sh
+++ b/graphics/mol2chemfig/docs/examples/phenol-as-submol.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/phenol-as-submol.tex b/graphics/mol2chemfig/docs/examples/phenol-as-submol.tex
index b51ef95581..b51ef95581 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/phenol-as-submol.tex
+++ b/graphics/mol2chemfig/docs/examples/phenol-as-submol.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/phenol-from-smiles-w.sh b/graphics/mol2chemfig/docs/examples/phenol-from-smiles-w.sh
index 6f25cbdde4..6f25cbdde4 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/phenol-from-smiles-w.sh
+++ b/graphics/mol2chemfig/docs/examples/phenol-from-smiles-w.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/phenol-from-smiles-wz.sh b/graphics/mol2chemfig/docs/examples/phenol-from-smiles-wz.sh
index 97c218a62f..97c218a62f 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/phenol-from-smiles-wz.sh
+++ b/graphics/mol2chemfig/docs/examples/phenol-from-smiles-wz.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/phenol-from-smiles.sh b/graphics/mol2chemfig/docs/examples/phenol-from-smiles.sh
index 5e1df1db25..5e1df1db25 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/phenol-from-smiles.sh
+++ b/graphics/mol2chemfig/docs/examples/phenol-from-smiles.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/phenol-smi-terse.tex b/graphics/mol2chemfig/docs/examples/phenol-smi-terse.tex
index 3793a018c5..3793a018c5 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/phenol-smi-terse.tex
+++ b/graphics/mol2chemfig/docs/examples/phenol-smi-terse.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/phenol-smi-wrapped.tex b/graphics/mol2chemfig/docs/examples/phenol-smi-wrapped.tex
index c6f70ef10e..c6f70ef10e 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/phenol-smi-wrapped.tex
+++ b/graphics/mol2chemfig/docs/examples/phenol-smi-wrapped.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/phenol-smi.tex b/graphics/mol2chemfig/docs/examples/phenol-smi.tex
index 0bc164867d..0bc164867d 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/phenol-smi.tex
+++ b/graphics/mol2chemfig/docs/examples/phenol-smi.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/phenol-with-hydrogens.tex b/graphics/mol2chemfig/docs/examples/phenol-with-hydrogens.tex
index c831a20d4b..c831a20d4b 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/phenol-with-hydrogens.tex
+++ b/graphics/mol2chemfig/docs/examples/phenol-with-hydrogens.tex
diff --git a/graphics/mol2chemfig/docs/examples/plp-arrows.sh b/graphics/mol2chemfig/docs/examples/plp-arrows.sh
new file mode 100755
index 0000000000..1095711b9f
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/plp-arrows.sh
@@ -0,0 +1,2 @@
+mol2chemfig -f -l plp plp.mol > plp.tex
+mol2chemfig -f -l plp2 plp2.mol > plp2.tex \ No newline at end of file
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/plp.mol b/graphics/mol2chemfig/docs/examples/plp.mol
index 09f686e869..09f686e869 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/plp.mol
+++ b/graphics/mol2chemfig/docs/examples/plp.mol
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/plp.sh b/graphics/mol2chemfig/docs/examples/plp.sh
index a351f09bc3..a351f09bc3 100755
--- a/graphics/mol2chemfig/doc/doc-source/examples/plp.sh
+++ b/graphics/mol2chemfig/docs/examples/plp.sh
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/plp.tex b/graphics/mol2chemfig/docs/examples/plp.tex
index 6dd82a1146..6dd82a1146 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/plp.tex
+++ b/graphics/mol2chemfig/docs/examples/plp.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/plp2.mol b/graphics/mol2chemfig/docs/examples/plp2.mol
index 8d1459f4fd..8d1459f4fd 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/plp2.mol
+++ b/graphics/mol2chemfig/docs/examples/plp2.mol
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/plp2.tex b/graphics/mol2chemfig/docs/examples/plp2.tex
index c0d352a655..c0d352a655 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/plp2.tex
+++ b/graphics/mol2chemfig/docs/examples/plp2.tex
diff --git a/graphics/mol2chemfig/docs/examples/printoptions.sh b/graphics/mol2chemfig/docs/examples/printoptions.sh
new file mode 100755
index 0000000000..eade23b8f8
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/printoptions.sh
@@ -0,0 +1 @@
+mol2chemfig 2> optionlist.tex \ No newline at end of file
diff --git a/graphics/mol2chemfig/docs/examples/setbondstyle.tex b/graphics/mol2chemfig/docs/examples/setbondstyle.tex
new file mode 100644
index 0000000000..792ee3aae7
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/setbondstyle.tex
@@ -0,0 +1,2 @@
+\setbondstyle[draw=magenta!50,-,line width=3pt,shorten <=2pt,shorten >=2pt]%
+ {draw=black,line width=0.5pt} \ No newline at end of file
diff --git a/graphics/mol2chemfig/doc/doc-source/examples/twisted.mol b/graphics/mol2chemfig/docs/examples/twisted.mol
index 0dca2407ae..0dca2407ae 100644
--- a/graphics/mol2chemfig/doc/doc-source/examples/twisted.mol
+++ b/graphics/mol2chemfig/docs/examples/twisted.mol
diff --git a/graphics/mol2chemfig/docs/examples/twisted.sh b/graphics/mol2chemfig/docs/examples/twisted.sh
new file mode 100755
index 0000000000..930bcb37e0
--- /dev/null
+++ b/graphics/mol2chemfig/docs/examples/twisted.sh
@@ -0,0 +1,3 @@
+mol2chemfig -t 2 -wn twisted.mol > twisted-n.tex
+mol2chemfig -t 2 -w twisted.mol > twisted-simple.tex
+mol2chemfig -t 2 -w -k 2-4 twisted.mol > twisted-k.tex
diff --git a/graphics/mol2chemfig/doc/doc-source/mol2chemfig-doc.tex b/graphics/mol2chemfig/docs/mol2chemfig-doc.tex
index fe6b0c971d..045de5bcfb 100644
--- a/graphics/mol2chemfig/doc/doc-source/mol2chemfig-doc.tex
+++ b/graphics/mol2chemfig/docs/mol2chemfig-doc.tex
@@ -3,7 +3,7 @@
\input{preamble}
\title{\mcf Documentation}
-\author{Version 1.4}
+\author{Version 1.5}
\begin{document}
@@ -18,6 +18,7 @@
\input{chapters/introduction}
\input{chapters/installation}
\input{chapters/context}
+\input{chapters/compatibility}
\input{chapters/help}
\input{chapters/tutorial}
\input{chapters/input-modes}
diff --git a/graphics/mol2chemfig/doc/doc-source/preamble.tex b/graphics/mol2chemfig/docs/preamble.tex
index a4a0fee312..f2f1a575ac 100644
--- a/graphics/mol2chemfig/doc/doc-source/preamble.tex
+++ b/graphics/mol2chemfig/docs/preamble.tex
@@ -1,11 +1,14 @@
\usepackage{
+ enumitem,
graphicx,
listings,
- paralist,
textcomp,
xspace
}
+\setlist[enumerate]{itemsep=0pt}
+\setlist[itemize]{itemsep=0pt}
+
% use postscript fonts
\usepackage{courier,times}
\usepackage[scaled=0.92]{helvet}
@@ -13,6 +16,7 @@
\usepackage[x11names]{xcolor}
\usepackage[margin=1.0in]{geometry}
+\usepackage[small]{titlesec}
% load mol2chemfig custom macros
\usepackage{mol2chemfig}
diff --git a/graphics/mol2chemfig/docs/test.tex b/graphics/mol2chemfig/docs/test.tex
new file mode 100644
index 0000000000..727f436f05
--- /dev/null
+++ b/graphics/mol2chemfig/docs/test.tex
@@ -0,0 +1,20 @@
+\documentclass[letterpaper,11pt]{article}
+
+\input{preamble}
+
+\title{\mcf Documentation}
+\author{Version 1.1e}
+
+\begin{document}
+
+\subsection{Working with sub-molecules}
+
+The package supplies a nifty mechanism to assemble larger molecules from predefined fragments, or sub-molecules. The following (hand-coded) example builds aspirin from two sub-molecules:
+
+%\lstinputlisting{hand-coded-tex/aspirin.tex}
+
+\input{hand-coded-tex/stuff}
+
+As a more advanced example, let us piece together the structure of Sodium Green, a fluorescent sodium indicator dye (the figure below was ripped from an information sheet by the supplier, Molecular Probes).
+
+\end{document}
diff --git a/graphics/mol2chemfig/install/mol2chemfig-1.5/PKG-INFO b/graphics/mol2chemfig/install/mol2chemfig-1.5/PKG-INFO
new file mode 100644
index 0000000000..f4ff6a8f5b
--- /dev/null
+++ b/graphics/mol2chemfig/install/mol2chemfig-1.5/PKG-INFO
@@ -0,0 +1,10 @@
+Metadata-Version: 1.0
+Name: mol2chemfig
+Version: 1.5
+Summary: Full version of mol2chemfig
+Home-page: http://chimpsky.uwaterloo.ca/mol2chemfig/
+Author: Michael Palmer
+Author-email: mpalmer@uwaterloo.ca
+License: The LaTeX project public license
+Description: UNKNOWN
+Platform: UNKNOWN
diff --git a/graphics/mol2chemfig/install/mol2chemfig-1.5/mol2chemfig b/graphics/mol2chemfig/install/mol2chemfig-1.5/mol2chemfig
new file mode 100755
index 0000000000..e79d893b80
--- /dev/null
+++ b/graphics/mol2chemfig/install/mol2chemfig-1.5/mol2chemfig
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+# unix version of the command line script
+
+import sys
+from mol2chemfig.processor import process
+
+success, result = process(rawargs=sys.argv[1:], progname=sys.argv[0])
+
+if success:
+ print result.render_user()
+else:
+ print >> sys.stderr, result
+
diff --git a/graphics/mol2chemfig/install/mol2chemfig-1.5/mol2chemfig.cmd b/graphics/mol2chemfig/install/mol2chemfig-1.5/mol2chemfig.cmd
new file mode 100644
index 0000000000..4ae3ea1fe1
--- /dev/null
+++ b/graphics/mol2chemfig/install/mol2chemfig-1.5/mol2chemfig.cmd
@@ -0,0 +1,7 @@
+@setlocal enableextensions & python -x %~f0 %* & goto :EOF
+# windows version of the command line script
+
+import sys
+from mol2chemfig.processor import process
+
+print process(rawargs=sys.argv[1:], progname=sys.argv[0])
diff --git a/graphics/mol2chemfig/install/mol2chemfig-1.5/setup.py b/graphics/mol2chemfig/install/mol2chemfig-1.5/setup.py
new file mode 100644
index 0000000000..c23ad6237a
--- /dev/null
+++ b/graphics/mol2chemfig/install/mol2chemfig-1.5/setup.py
@@ -0,0 +1,14 @@
+from distutils.core import setup
+
+setup(name='mol2chemfig',
+ version='1.5',
+ description='Full version of mol2chemfig',
+ #summary='Full version of mol2chemfig',
+ license='The LaTeX project public license',
+ package_dir={'mol2chemfig':'src'},
+ author='Michael Palmer',
+ author_email='mpalmer@uwaterloo.ca',
+ url='http://chimpsky.uwaterloo.ca/mol2chemfig/',
+ scripts=['mol2chemfig','mol2chemfig.cmd'],
+ packages=["mol2chemfig"]
+)
diff --git a/graphics/mol2chemfig/install/mol2chemfig-1.5/src/__init__.py b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/__init__.py
new file mode 100644
index 0000000000..0f1cfe8b8e
--- /dev/null
+++ b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/__init__.py
@@ -0,0 +1 @@
+# make this a python package \ No newline at end of file
diff --git a/graphics/mol2chemfig/install/mol2chemfig-1.5/src/atom.py b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/atom.py
new file mode 100644
index 0000000000..bb814e8a5e
--- /dev/null
+++ b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/atom.py
@@ -0,0 +1,183 @@
+import math, string
+
+import chemfig_mappings as cfm
+
+from common import debug
+
+# some atoms should carry their hydrogens to the left, rather than
+# to the right. This is applied to solitary atoms, but not to bonded
+# functional groups that contain those elements.
+
+hydrogen_lefties = "O S Se Te F Cl Br I At".split() # I hope these are all ...
+
+class Atom(object):
+ '''
+ wrapper around toolkit atom object, augmented with coordinates
+ helper class for molecule.Molecule
+ '''
+ explicit_characters = set(string.ascii_uppercase + string.digits)
+
+ quadrant_turf = 80 # 80 degrees have to remain free on either side
+
+ quadrants = [ # quadrants for hydrogen placement
+ [0, 0, 'east'],
+ [1, 180, 'west'],
+ [2, 270, 'south'],
+ [3, 90, 'north']
+ ]
+
+ charge_positions = [ # angles for placement of detached charges
+ [0, 15, 'top_right'],
+ [1,165, 'top_left'],
+ [2, 90, 'top_center'],
+ [3,270, 'bottom_center'],
+ [4,345, 'bottom_right'],
+ [5,195, 'bottom_left']
+ ]
+
+ charge_turf = 50 # reserved angle for charges - needs to be big enough for 2+
+
+ def __init__(self, options, idx, x, y, element, hydrogens, charge, radical, neighbors):
+ self.options = options
+ self.idx = idx
+ self.x = x
+ self.y = y
+ self.element = element
+ self.hydrogens = hydrogens
+ self.charge = charge
+ self.radical = radical
+ self.neighbors = neighbors # the indexes only
+
+ # angles of all attached bonds - to be populated later
+ self.bond_angles = []
+
+ # self.explicit = False # flag for explicitly printed atoms - set later
+ marker = self.options.get('markers', None)
+ if marker is not None:
+ self.marker = "%s%s" % (marker, self.idx + 1)
+ else:
+ self.marker = ""
+
+
+ def _score_angle(self, a, b, turf):
+ '''
+ helper. calculates absolute angle between a and b.
+ 0 <= angle <= 180
+ then compares to turf angle and returns a score > 0
+ if angle falls within turf.
+ '''
+ diff = (a-b) % 360
+ angle = min(diff,360-diff)
+
+ return (max(0, turf - angle)) ** 2
+
+
+ def _score_angles(self, choices, turf):
+ '''
+ backend for score_angles
+ '''
+
+ aux = []
+
+ for priority, choice_angle, name in choices:
+
+ score = 0
+
+ for bond_angle in self.bond_angles:
+ score += self._score_angle(choice_angle, bond_angle, turf)
+
+ aux.append((score, priority, name))
+
+ aux.sort()
+
+ #if self.element == 'Cl':
+ #debug(aux)
+
+ named = [a[-1] for a in aux]
+ return named
+
+
+ def score_angles(self):
+ '''
+ determine which positions
+
+ We use one score for the placement of hydrogens w/ or w/o charge,
+ and a separate one for the placement of charges only.
+
+ Atoms: precedence east, west, south, north
+ tolerated impingement 10 degrees
+
+ Charges: precedence top right, top left, top straight,
+ bottom straight, others
+ '''
+ if len(self.bond_angles) > 0: # this atom is bonded
+ quadrants = self._score_angles(self.quadrants, self.quadrant_turf)
+ self.first_quadrant = quadrants[0]
+ self.second_quadrant = quadrants[1] # 2nd choice may be used for radical electrons
+
+ else: # this atom is solitary
+ if self.element in hydrogen_lefties:
+ self.first_quadrant = 'west'
+ self.second_quadrant = 'east'
+ else:
+ self.first_quadrant = 'east'
+ self.second_quadrant = 'west'
+
+ self.charge_angle = self._score_angles(self.charge_positions, self.charge_turf)[0]
+
+
+ def render_phantom(self):
+ '''
+ render a bond that closes a ring or loop, or for
+ late-rendered cross bonds. The target atom
+ is represented by a phantom.
+
+ This relies on .render() having been called earlier, which
+ it will be - atoms always precede their phantoms during
+ molecule tree traversal.
+ '''
+ atom_code = self.phantom
+ comment_code = cfm.format_closure_comment(
+ self.options,
+ self.idx + 1,
+ self.element,
+ self.hydrogens,
+ self.charge
+ )
+ return atom_code, comment_code
+
+
+ def render(self):
+ '''
+ render the atom and a comment
+ '''
+ atom_code, self.string_pos, \
+ self.phantom, self.phantom_pos = cfm.format_atom(
+ self.options,
+ self.idx + 1,
+ self.element,
+ self.hydrogens,
+ self.charge,
+ self.radical,
+ self.first_quadrant,
+ self.second_quadrant,
+ self.charge_angle
+ )
+
+ comment_code = cfm.format_atom_comment(
+ self.options,
+ self.idx + 1,
+ self.element,
+ self.hydrogens,
+ self.charge
+ )
+
+ marker_code = cfm.format_marker(self.marker)
+ if marker_code:
+ comment_code = " " # force an empty comment, needed after markers
+
+ self.explicit = bool(self.explicit_characters & set(atom_code))
+ # debug(self.idx, atom_code, self.explicit)
+ return marker_code + atom_code, comment_code
+
+
diff --git a/graphics/mol2chemfig/install/mol2chemfig-1.5/src/bond.py b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/bond.py
new file mode 100644
index 0000000000..9ea2879121
--- /dev/null
+++ b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/bond.py
@@ -0,0 +1,558 @@
+'''
+My name is Bond. JAMES Bond.
+'''
+
+from copy import deepcopy, copy
+from math import atan, tan, pi
+
+import chemfig_mappings as cfm
+from common import debug
+
+# bond stereo properties and valences
+from indigo import Indigo
+
+# Indigo.UP : stereo "up" bond
+# Indigo.DOWN : stereo "down" bond
+# Indigo.EITHER : stereo "either" bond
+# Indigo.CIS : "Cis" double bond
+# Indigo.TRANS : "Trans" double bond
+# zero : not a stereo bond of any kind
+
+# bond_type: 1,2,3,4 for single, double, triple, aromatic
+
+# map indigo's bond specifiers to m2cf custom ones.
+bond_mapping = {
+ 1 : 'single',
+ 2 : 'double',
+ 3 : 'triple',
+ 4 : 'aromatic', # not really used
+ Indigo.UP : 'upto',
+ Indigo.DOWN : 'downto',
+ Indigo.EITHER : 'either'
+}
+
+def compare_positions(x1, y1, x2, y2):
+ '''
+ calculate distance and angle between the
+ coordinates of two atoms.
+
+ is the same as atan2 from math?
+ '''
+
+ xdiff = x2 - x1
+ ydiff = y2 - y1
+
+ length = (xdiff**2 + ydiff**2) ** 0.5
+
+ if xdiff == 0:
+ if ydiff < 0:
+ angle = 270
+ else:
+ angle = 90
+
+ else:
+ raw_angle = atan(abs(ydiff / xdiff)) * 180/pi
+
+ if ydiff >= 0:
+ if xdiff > 0:
+ angle = raw_angle
+ else:
+ angle = 180 - raw_angle
+ else:
+ if xdiff > 0:
+ angle = -raw_angle
+ else:
+ angle = 180 + raw_angle
+
+ return length, angle
+
+
+class Bond(object):
+ '''
+ helper class for molecule.Molecule
+
+ a bond connects two atoms and computes its angle and length
+ from those. It knows how to render itself to chemfig. Bonds
+ can be hooks.
+
+ On instantiation, the bond is not part of a hierarchy yet, so
+ we can assign a parent. This has to occur later. So, initially
+ we just know the start and the end atom.
+ '''
+ is_last = False # flag for bond that is the last descendant of
+ # the exit bond - needed in rare case in
+ # cases for bond formatting.
+ to_phantom = False # flag for bonds that should render their end atoms
+ # as phantoms: Ring closures and cross bonds
+ is_trunk = False # by default, bonds are not part of the trunk
+ parent = None # will be assigned when bonds are added to the tree.
+ clockwise = 0 # only significant in double bonds in rings that are
+ # not drawn with aromatic circles
+
+ def __init__(self,
+ options,
+ start_atom,
+ end_atom,
+ bond_type=None,
+ stereo=0):
+
+ self.options = options
+ self.start_atom = start_atom
+ self.end_atom = end_atom
+
+ # special styles that get rendered via tikz
+ self.tikz_styles = set()
+ self.tikz_values = {}
+
+ if stereo in (Indigo.UP, Indigo.DOWN):
+ if self.options['flip_vertical'] != self.options['flip_horizontal']:
+ stereo = Indigo.UP + Indigo.DOWN - stereo
+
+ if stereo in (Indigo.UP, Indigo.DOWN, Indigo.EITHER): # implies single bond
+ self.bond_type = bond_mapping[stereo]
+
+ else: # no interesting stereo property - simply go with bond valence
+ # or else keep passed-in string specifier
+ self.bond_type = bond_mapping.get(bond_type, bond_type)
+
+ # bonds now are also the nodes in the molecule tree. These two
+ # attributes must be set later, when the tree is created.
+ self.descendants = []
+
+ self.length, angle = self.bond_dimensions()
+ # length is adjusted and rounded later, after all is parsed
+
+ # apply molecule rotation
+ angle += self.options['rotate']
+ self.angle = angle
+
+ # define marker
+ marker = self.options.get('markers', None)
+
+ if marker is not None:
+ ids = [self.start_atom.idx +1, self.end_atom.idx +1]
+ ids.sort()
+ self.marker = '%s%s-%s' % (marker, ids[0], ids[1])
+ else:
+ self.marker = ""
+
+
+ def bond_dimensions(self):
+ '''
+ determine bond angle and distance between two atoms
+ '''
+ return compare_positions(
+ self.start_atom.x,
+ self.start_atom.y,
+ self.end_atom.x,
+ self.end_atom.y
+ )
+
+
+ def is_clockwise(self, center_x, center_y):
+ '''
+ determine whether the bond will be drawn clockwise
+ or counterclockwise relative to center
+ '''
+ if self.clockwise: # assign only once
+ return
+
+ center_dist, center_angle = compare_positions(
+ self.end_atom.x,
+ self.end_atom.y,
+ center_x,
+ center_y)
+
+ # bond is already rotated at this stage, so we need to
+ # rotate the ring center also
+ center_angle += self.options['rotate']
+ center_kink = (center_angle - self.angle) % 360
+
+ if center_kink > 180:
+ self.clockwise = 1
+ else:
+ self.clockwise = -1
+
+
+ def clone(self):
+ '''
+ deepcopy but keep original atoms
+ '''
+ c = copy(self)
+ # c.start_atom, c.and_atom = self.start_atom, self.end_atom
+
+ return c
+
+
+ def invert(self):
+ '''
+ draw a bond backwards.
+ '''
+ c = deepcopy(self)
+ c.start_atom, c.end_atom = self.end_atom, self.start_atom
+ c.angle = (c.angle + 180) % 360
+
+ if self.bond_type == 'upto':
+ c.bond_type = 'upfrom'
+ elif self.bond_type == 'downto':
+ c.bond_type = 'downfrom'
+
+ return c
+
+
+ def set_link(self):
+ '''
+ make this bond an invisible link. this also cancels
+ any other tikz styles, and removes the marker.
+ '''
+ self.bond_type = "link"
+ self.tikz_styles = set()
+ self.tikz_values = {}
+ self.marker = ""
+
+
+ def set_cross(self, last=False):
+ '''
+ draw this bond crossing over another.
+ '''
+ # debug(self.start_atom.idx, self.end_atom.idx, self.tikz_styles, self.tikz_values)
+ start_angles = self.upstream_angles()
+ end_angles = self.downstream_angles()
+
+ start_angle = min(start_angles.values())
+ start = max(10, self.cotan100(start_angle))
+
+ end_angle = min(end_angles.values())
+ end = max(10, self.cotan100(end_angle))
+
+ self.tikz_styles.add("cross")
+ self.tikz_values.update( dict(bgstart=start, bgend=end))
+
+ self.is_last = last
+
+
+ def _adjoining_angles(self, atom, inversion_angle=0):
+ '''
+ determine the narrowest upstream or downstream angles
+ on the left and the right.
+ '''
+ raw_angles = atom.bond_angles[:]
+ raw_angles = [int(round(a)) % 360 for a in raw_angles]
+
+ reference_angle = int(round(self.angle - inversion_angle)) % 360
+ # debug(atom.idx, inversion_angle, reference_angle, raw_angles)
+
+ raw_angles.remove(reference_angle)
+
+ if not raw_angles: # no other bonds attach to start atom
+ return None, None
+
+ angles = [(a - reference_angle) % 360 for a in raw_angles]
+ angles.sort()
+
+ return int(round(angles[0])), int(round(angles[-1] ))
+
+
+ def upstream_angles(self):
+ '''
+ determine the narrowest upstream left and upstream right angle.
+ '''
+ first, last = self._adjoining_angles(self.start_atom)
+
+ # for the right angle, convert outer to inner
+ if last is not None:
+ last = 360-last
+
+ return dict(left=first, right=last)
+
+
+ def downstream_angles(self):
+ '''
+ determine the narrowest downstream left and downstream right angle.
+ '''
+ first, last = self._adjoining_angles(self.end_atom, 180)
+
+ if last is not None:
+ # for the left angle, convert outer to inner
+ last = 360-last
+
+ return dict(left=last, right=first)
+
+
+ def angle_penalty(self, angle):
+ '''
+ scoring function used in picking sides for second
+ stroke of double bond
+ '''
+ if angle is None:
+ return 0
+
+ return (angle - 105) ** 2
+
+
+ def cotan100(self,angle):
+ '''
+ 100 times cotan of angle, rounded
+ '''
+ _tan = tan(angle * pi/180)
+ return int(round(100/_tan))
+
+
+ def shorten_stroke(self, same_angle, other_angle):
+ '''
+ determine by how much to shorten the second stroke
+ of a double bond.
+ '''
+ if same_angle is None: # other_angle will be, too; don't shorten.
+ return 0
+
+ if same_angle <= 180:
+ angle = 0.5 * same_angle
+ else:
+ if 210 < same_angle < 270:
+ angle = same_angle - 180
+ elif 210 < other_angle < 270:
+ angle = other_angle - 180
+ else:
+ angle = 90
+
+ return self.cotan100(angle)
+
+
+ def fancy_double(self):
+ '''
+ work out the parameters for rendering a fancy double bond.
+
+ we need to decide whether the second stroke should be to
+ the left or the right of the main stroke, and also by
+ how much to shorten the start and and of the second stroke.
+ '''
+ # if we are in a ring, the second stroke should be inside.
+
+ start_angles = self.upstream_angles()
+ end_angles = self.downstream_angles()
+
+ # outside rings and if the double bond connects to explicit atoms,
+ # plain symmetric double bonds tend to look better.
+
+ if not self.clockwise and \
+ (self.start_atom.explicit or self.end_atom.explicit):
+
+ if self.start_atom.explicit and self.end_atom.explicit:
+ return None
+
+ elif self.start_atom.explicit and \
+ (end_angles['left'] is None or \
+ (90 <= abs(end_angles['left']) <= 135 and \
+ 90 <= abs(end_angles['right']) <= 135)):
+ return None
+
+ elif self.end_atom.explicit and \
+ (start_angles['left'] is None or \
+ (90 <= abs(start_angles['left']) <= 135 and \
+ 90 <= abs(start_angles['right']) <= 135)):
+ return None
+
+ # at this point we are looking at either only implicit atoms
+ # or extreme angles.
+ if self.clockwise == -1:
+ side = "left"
+
+ elif self.clockwise == 1:
+ side = "right"
+
+ else: # not in a ring. use scoring function to pick sides.
+ _ap = self.angle_penalty
+
+ left_penalty = _ap(start_angles['left']) + _ap(end_angles['left'])
+ right_penalty = _ap(start_angles['right']) + _ap(end_angles['right'])
+
+ if left_penalty < right_penalty:
+ side = "left"
+ elif left_penalty > right_penalty:
+ side = "right"
+ else: # penalties equal - try to pick sides consistently
+ if abs(self.angle - 44.5) < 90:
+ side = "left"
+ else:
+ side = "right"
+
+ if self.start_atom.explicit:
+ start = 0
+ else:
+ if side == 'left':
+ start = self.shorten_stroke(start_angles['left'], start_angles['right'])
+ else:
+ start = self.shorten_stroke(start_angles['right'], start_angles['left'])
+
+ if self.end_atom.explicit:
+ end = 0
+ else:
+ if side == 'left':
+ end = self.shorten_stroke(end_angles['left'], end_angles['right'])
+ else:
+ end = self.shorten_stroke(end_angles['right'], end_angles['left'])
+
+ return side, start, end
+
+
+ def fancy_triple(self):
+ '''
+ work out parameters for fancy triple bond. We don't
+ need to choose sides here, just calculate the required
+ line shortening.
+ '''
+ end_angles = self.downstream_angles()
+
+ if self.start_atom.explicit:
+ start = 0
+ else:
+ start_angles = self.upstream_angles().values()
+ if start_angles[0] is not None:
+ start = self.cotan100(0.5 * min(start_angles))
+ else:
+ start = 0
+
+ if self.end_atom.explicit:
+ end = 0
+ else:
+ end_angles = self.downstream_angles().values()
+ if end_angles[0] is not None:
+ end = self.cotan100(0.5 * min(end_angles))
+ else:
+ end = 0
+
+ return start, end
+
+
+ def bond_to_chemfig(self):
+ '''
+ delegate to chemfig_mappings module to render
+ the bond code, without the atom
+ '''
+
+ if self.to_phantom:
+ end_string_pos = self.end_atom.phantom_pos
+ else:
+ end_string_pos = self.end_atom.string_pos
+
+ if self.options['fancy_bonds'] \
+ and self.bond_type in ('double', 'triple'):
+
+ # debug("b2c before ", self.start_atom.idx, self.end_atom.idx, self.tikz_styles, self.tikz_values)
+
+ if self.bond_type == 'double':
+ fd = self.fancy_double()
+
+ if fd is not None:
+ side, start, end = fd
+
+ self.tikz_styles.add("double")
+ self.tikz_styles.add(side)
+ self.tikz_values.update( dict(start=start, end=end) )
+ self.bond_type = 'decorated'
+
+ elif self.bond_type == 'triple':
+ self.tikz_styles.add('triple')
+ start, end = self.fancy_triple()
+
+ self.tikz_values.update( dict(start=start, end=end) )
+ self.bond_type = 'decorated'
+
+ # debug("b2c after ", self.start_atom.idx, self.end_atom.idx, self.tikz_styles, self.tikz_values)
+
+ code = cfm.format_bond(
+ self.options,
+ self.angle,
+ self.parent.angle,
+ self.bond_type,
+ self.clockwise,
+ self.is_last,
+ self.length,
+ self.start_atom.string_pos,
+ end_string_pos,
+ self.tikz_styles,
+ self.tikz_values,
+ self.marker
+ )
+
+ return code
+
+ def indent(self, level, bond_code, atom_code='', comment_code=''):
+ stuff = ' ' * self.options['indent'] * level \
+ + bond_code.rjust(cfm.BOND_CODE_WIDTH) \
+ + atom_code
+
+ if comment_code:
+ stuff += "% " + comment_code
+
+ return stuff.rstrip()
+
+
+ def render(self, level):
+ '''
+ render bond and trailing atom.
+ '''
+ if not self.to_phantom:
+ atom_code, comment_code = self.end_atom.render()
+ else:
+ atom_code, comment_code = self.end_atom.render_phantom()
+
+ bond_code = self.bond_to_chemfig()
+
+ return self.indent(level, bond_code, atom_code, comment_code)
+
+
+class DummyFirstBond(Bond):
+ '''
+ semi-dummy class that only takes an endatom, wich is the
+ first atom in the molecule, and just renders that.
+
+ The other dummy attributes only exist to play nice with
+ the molecule class.
+ '''
+
+ def __init__(self, options, end_atom):
+ self.options = options
+ self.end_atom = end_atom
+ self.angle = None
+ self.descendants = []
+ self.length = None
+
+ def bond_to_chemfig(self):
+ return '' # empty bond code before first atom
+
+
+class AromaticRingBond(Bond):
+ '''
+ A gross hack to render the circle inside an aromatic ring
+ as a node in the regular bond hierarchy.
+ '''
+ descendants = []
+ scale = 1.5 # 1.5 corresponds to chemfig's ring size
+
+ def __init__(self, options, parent, angle, length, inner_r):
+ self.options = options
+ self.angle = cfm.num_round(angle,1) % 360
+ if parent is not None:
+ self.parent_angle = parent.angle
+ else:
+ self.parent_angle = None
+ self.length = cfm.num_round(length, 2)
+ self.radius = cfm.num_round(self.scale * inner_r, 2)
+
+ def render(self, level):
+ '''
+ there is no atom to render, so we just call chemfig_mapping
+ on our own attributes.
+ '''
+ ring_bond_code, ring_code, comment = cfm.format_aromatic_ring(
+ self.options,
+ self.angle,
+ self.parent_angle,
+ self.length,
+ self.radius)
+
+ return self.indent(level, ring_bond_code, ring_code, comment)
+
+
diff --git a/graphics/mol2chemfig/install/mol2chemfig-1.5/src/chemfig_mappings.py b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/chemfig_mappings.py
new file mode 100644
index 0000000000..384d9129c8
--- /dev/null
+++ b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/chemfig_mappings.py
@@ -0,0 +1,487 @@
+'''
+definitions and code to translate the molecule tree to chemfig
+
+this code will only make sense to you if you are familiar with
+the TeX syntax defined by the chemfig package.
+'''
+
+import textwrap
+import common
+
+from common import debug
+
+BOND_CODE_WIDTH = 50 # space for bonds - generous upfront, will be trimmed at the end
+TERSE_LINE_WIDTH = 75 # in terse code format, force linebreaks
+
+def num_round(num, sig):
+ '''
+ round and, if applicable, return integer instead of float
+ '''
+ res = round(num, sig)
+ if res == int(res):
+ return int(res)
+ return res
+
+bond_codes = dict( # bond_type -> chemfig bond code. defaults to '-'
+ double = '=',
+ triple = '~',
+ upto = '<',
+ downto = '<:',
+ upfrom = '>',
+ downfrom = '>:'
+)
+
+bond_type_tikz = dict( # bond type -> tikz
+ link = 'draw=none',
+ either = 'mcfwavy'
+)
+
+bond_styles = dict( # bond style -> tikz template
+ cross = 'mcfx={%(bgstart)s}{%(bgend)s}',
+ double_left = 'dbl={%(start)s}{%(end)s}',
+ double_right = 'dbr={%(start)s}{%(end)s}',
+ triple = 'trpl={%(start)s}{%(end)s}',
+ # combined styles for double, triple and cross
+ cross_double_left = 'dblx={%(start)s}{%(end)s}{%(bgstart)s}{%(bgend)s}',
+ cross_double_right = 'dbrx={%(start)s}{%(end)s}{%(bgstart)s}{%(bgend)s}',
+ cross_triple = 'trplx={%(start)s}{%(end)s}{%(bgstart)s}{%(bgend)s}'
+)
+
+bond_style_shortcuts = { # style short cuts for double bonds in hexagons etc
+ "dbr={58}{58}" : "drh",
+ "dbl={58}{58}" : "dlh",
+ "dbr={0}{58}" : "drhe",
+ "dbl={0}{58}" : "dlhe",
+ "dbr={58}{0}" : "drhs",
+ "dbl={58}{0}" : "dlhs",
+ "dbr={0}{0}" : "drn",
+ "dbl={0}{0}" : "dln"
+}
+
+macro_templates = dict( # various custom LaTeX macros
+
+ ## templates for charges
+ plus_charge = r'\mcfplus',
+ minus_charge = r'\mcfminus',
+
+ ## template for phantom that forms the end of ring-closing bond
+ phantom = r'\phantom{%s}', # phantom at end of ring-closing bonds
+
+ ## template for drawing a circle inside an aromatic ring
+ aromatic_circle = r'\mcfcringle{%s}',
+
+ ## template for the bond connecting the circle to the atom
+ aromatic_circle_bond = r'-[%(angle)s,%(length)s,,,draw=none]',
+
+ ## cross bonds
+ cross_blank = r'draw=none',
+ cross_draw = r'mcfcrossbond',
+
+ ## markers identifying atoms and bonds
+ marker = r'@{%s}'
+)
+
+radical_templates = dict(
+ east = r'\lewis{0%s,%s}',
+ north = r'\lewis{2%s,%s}',
+ west = r'\lewis{4%s,%s}',
+ south = r'\lewis{6%s,%s}'
+)
+
+atom_templates = dict(
+ ## templates for atoms, specialized for different numbers and preferred
+ ## quadrants of attached hydrogens and charges
+
+ # atom numbers
+ atom_no = dict(
+ empty = (r'\mcfatomno{%(number)s}', 0),
+ east = (r'\mcfright{%(element)s}{\mcfatomno{%(number)s}}', 0),
+ west = (r'\mcfleft{\mcfatomno{%(number)s}}{%(element)s}', 0),
+ north = (r'\mcfabove{%(element)s}{\mcfatomno{%(number)s}}', 0),
+ south = (r'\mcfbelow{%(element)s}{\mcfatomno{%(number)s}}', 0)
+ ),
+
+ neutral = dict(
+ # one hydrogen
+ one_h = dict(
+ east = (r'%(element)sH', 1),
+ west = (r'H%(element)s', 2),
+ north = (r'\mcfabove{%(element)s}{H}', 0),
+ south = (r'\mcfbelow{%(element)s}{H}', 0)
+ ),
+
+ # multiple hydrogens
+ more_h = dict(
+ east = (r'%(element)sH_%(hydrogens)s', 1),
+ west = (r'H_%(hydrogens)s%(element)s', 2),
+ north = (r'\mcfabove{%(element)s}{\mcfright{H}{_%(hydrogens)s}}', 0),
+ south = (r'\mcfbelow{%(element)s}{\mcfright{H}{_%(hydrogens)s}}', 0)
+ ),
+ ),
+
+ # charged
+ charged = dict(
+ no_h = dict(
+ top_right = (r'\mcfright{%(element)s}{^{%(charge)s}}', 0),
+ top_left = (r'^{%(charge)s}%(element)s', 2),
+ top_center = (r'\mcfabove{%(element)s}{_{%(charge)s}}', 0),
+ bottom_right = (r'\mcfright{%(element)s}{_{%(charge)s}}', 0),
+ bottom_left = (r'_{%(charge)s}%(element)s', 2),
+ bottom_center = (r'\mcfbelow{%(element)s}{^{%(charge)s}}', 0)
+ ),
+
+ # one hydrogen
+ one_h = dict(
+ east = (r'%(element)sH^{%(charge)s}', 1),
+ h_west = (r'^{%(charge)s}H%(element)s', 3),
+ north = (r'\mcfaboveright{%(element)s}{H}{^{%(charge)s}}',0),
+ south = (r'\mcfbelowright{%(element)s}{H}{^{%(charge)s}}',0)
+ ),
+
+ # more hydrogens
+ more_h = dict(
+ east = (r'%(element)sH_%(hydrogens)s^{%(charge)s}', 1),
+ west = (r'^{%(charge)s}H_%(hydrogens)s%(element)s', 3),
+ north = (r'\mcfaboveright{%(element)s}{H}{^{%(charge)s}_%(hydrogens)s}',0),
+ south = (r'\mcfbelowright{%(element)s}{H}{^{%(charge)s}_%(hydrogens)s}',0)
+ )
+ )
+)
+
+
+# helpers for bond formatting
+
+def format_angle(options, angle, parent_angle):
+ '''
+ format prefix and number for bond angle
+ '''
+ if options['relative_angles'] and parent_angle is not None:
+ angle -= parent_angle
+ prefix = '::'
+ else:
+ prefix = ':'
+
+ angle = num_round(angle, options['angle_round'])
+
+ return prefix + str(angle % 360)
+
+
+def specifier_default(val, default):
+ '''
+ set bond specifier default values to ""
+ '''
+ if val == default:
+ return ""
+ return str(val)
+
+# the master bond formatter
+
+def format_bond(options,
+ angle,
+ parent_angle,
+ bond_type,
+ clockwise,
+ is_last,
+ length,
+ departure,
+ arrival,
+ tikz_styles,
+ tikz_values,
+ marker):
+ '''
+ render the bond code for one atom; the atom itself is
+ rendered separately in format_atom
+ '''
+
+ # debug(tikz_styles, tikz_values)
+
+ if angle is None: # angle is None -- first atom only. Is this ever used? Shouldn't
+ return '' # let's try to eliminate once the rest is working
+
+ angle = format_angle(options, angle, parent_angle)
+
+ angle = specifier_default(angle, ':0')
+
+ length = num_round(length, options['bond_round'])
+ length = specifier_default(length, 1)
+
+ departure = specifier_default(departure, 0)
+ arrival = specifier_default(arrival, 0)
+
+ bond_code = bond_codes.get(bond_type, '-')
+
+ tikz_filled = []
+
+ btt = bond_type_tikz.get(bond_type, None)
+ if btt is not None:
+ tikz_filled.append(btt)
+
+ if tikz_styles:
+ key = '_'.join(sorted(list(tikz_styles)))
+
+ tikz = bond_styles[key] % tikz_values
+ tikz_filled.append(tikz)
+
+ if "cross" in key and not is_last: # departure atom is empty or a phantom, so
+ departure = "" # at most 1 character. is_last guards against
+ # edge case.
+
+ tikz = ','.join(tikz_filled)
+ tikz = bond_style_shortcuts.get(tikz, tikz) # replace tikz with shortcut if available
+
+ specifiers = [angle, length, departure, arrival, tikz]
+ specifiers = ','.join(specifiers).rstrip(',')
+
+ if marker:
+ specifiers = format_marker(marker) + specifiers
+
+ if specifiers:
+ specifiers = '[%s]' % specifiers
+
+ # modify double bonds in non-aromatic rings
+ if bond_type == 'double' and clockwise != 0:
+ if clockwise == 1:
+ modifier = '_'
+ else:
+ modifier = '^'
+ else:
+ modifier = ''
+
+ return bond_code + modifier + specifiers
+
+
+
+def fill_atom(keys, data, phantom, phantom_pos=0):
+ '''
+ helper for finalizing atom code. phantom_pos is the
+ target position of a bond attaching to a phantom;
+ currently, this is always 0, but if phantoms
+ should become more elaborate, that might change.
+ '''
+ thing = atom_templates[keys[0]]
+
+ # drill down into the template dict
+ for key in keys[1:]:
+ thing = thing[key]
+
+ template, string_pos = thing
+ return template % data, string_pos, phantom, phantom_pos
+
+
+def format_marker(marker):
+ '''
+ used for both bonds and atoms
+ '''
+ if marker:
+ marker = macro_templates['marker'] % marker
+ return marker
+
+
+def format_atom(options,
+ idx,
+ element,
+ hydrogens,
+ charge,
+ radical,
+ first_quadrant,
+ second_quadrant,
+ charge_angle):
+ '''
+ render an atom with hydrogens and charges. Return
+ - the chemfig code of the rendered atom
+ - the string position for incoming bonds to attach to
+ - a phantom string to be used for closing rings. We do this
+ here because we don't want to duplicate all those case
+ distinctions somewhere else. In most cases, the phantom
+ string is never used though.
+ '''
+
+ _mt = macro_templates # shortcuts
+ _at = atom_templates
+
+ # collect elements in a dict that then is used to fill
+ # the configured string templates.
+
+ # first, check whether we have a radical
+ if radical == 0:
+ radical_element = element
+ else:
+ if radical == 1:
+ radical_symbol = '.'
+ else:
+ radical_symbol = ':'
+ if hydrogens:
+ radical_quadrant = second_quadrant
+ else:
+ radical_quadrant = first_quadrant
+ radical_element = radical_templates[radical_quadrant] % (radical_symbol, element)
+
+ data = dict(
+ number = idx,
+ hydrogens = hydrogens,
+ element = radical_element
+ )
+
+ # we almost always need the same phantom string, so we prepare it once
+ element_phantom = _mt['phantom'] % data['element']
+
+ # deal with atom numbers first
+ if options['atom_numbers']:
+ if element == 'C' and not options['show_carbons']:
+ phantom = _mt['phantom'] % idx
+ keys = ('atom_no', 'empty')
+ return fill_atom(keys, data, phantom)
+
+ # not an empty carbon
+ keys = ('atom_no', first_quadrant)
+ return fill_atom(keys, data, element_phantom)
+
+ ## full atoms, no numbers
+
+ # neutrals
+ if charge == 0:
+
+ # empty carbons. This case is so simple we don't use a template.
+ if data['element'] == 'C' \
+ and not options['show_carbons'] \
+ and (not options['show_methyls'] \
+ or hydrogens < 3):
+ return '', 0, '', 0
+
+ # next simplest case: neutral atom without hydrogens
+ if not hydrogens:
+ return data['element'], 0, element_phantom, 0
+
+ # one or more hydrogens
+ if hydrogens == 1:
+ keys = ('neutral', 'one_h', first_quadrant)
+ else:
+ keys = ('neutral', 'more_h', first_quadrant)
+ return fill_atom(keys, data, element_phantom)
+
+
+ ## at this point, we have a charged atom
+
+ # format dict entry for charge, as it is configurable
+ if charge > 0:
+ data['charge'] = _mt['plus_charge']
+ else:
+ data['charge'] = _mt['minus_charge']
+
+ if abs(charge) > 1:
+ data['charge'] = str(abs(charge)) + data['charge']
+
+ if not hydrogens:
+ keys = ('charged', 'no_h', charge_angle)
+ elif hydrogens == 1:
+ keys = ('charged', 'one_h', first_quadrant)
+ else:
+ keys = ('charged', 'more_h', first_quadrant)
+
+ return fill_atom(keys, data, element_phantom)
+
+
+def format_atom_comment(options,
+ idx,
+ element,
+ hydrogens,
+ charge):
+ '''
+ render an optional end-of-line comment after a regular atom
+ '''
+ if options['terse']:
+ return ''
+ return str(idx)
+
+def format_closure_comment(options,
+ idx,
+ element,
+ hydrogens,
+ charge):
+ '''
+ render an optional end of line comment after a ring-closing bond
+ '''
+ if options['terse']:
+ return ''
+ return '-> %s' % idx
+
+
+def format_aromatic_ring(options,
+ angle,
+ parent_angle,
+ length,
+ radius):
+
+ values = dict(
+ angle=format_angle(options, angle, parent_angle),
+ length=specifier_default(length, 1)
+ )
+
+ ring_bond_code = macro_templates['aromatic_circle_bond'] % values
+ ring_code = macro_templates['aromatic_circle'] % radius
+
+ if options['terse']:
+ comment = ''
+ else:
+ comment = '(o)'
+
+ return ring_bond_code, ring_code, comment
+
+
+def strip_output(output_list):
+ '''
+ remove white space and comments
+ '''
+ stripped = []
+
+ for line in output_list:
+ stripped.append(line.split('%')[0].strip())
+
+ stripped.reverse()
+
+ chunked = []
+
+ acc = ''
+
+ while stripped:
+ popped = stripped.pop()
+ if len(acc) + len (popped) > TERSE_LINE_WIDTH:
+ chunked.append(acc)
+ acc = popped
+ else:
+ acc += popped
+ if acc:
+ chunked.append(acc)
+
+ return chunked
+
+
+def format_output(options, output_list):
+ '''
+ optionally wrap the translated output into a command,
+ to ease inclusion in LaTeX documents with \input
+ '''
+ # first, do a bit of prettification by removing excessive
+ # indentation
+ _indent = ' ' * options['indent']
+
+ _out = '\n'.join(output_list)
+ _out = textwrap.dedent(_out).splitlines()
+
+ output_list = [_indent + l for l in _out]
+
+ if options['submol_name'] is not None:
+ output_list.insert(0, r'\definesubmol{%s}{' % options['submol_name'])
+ output_list.append(r'}')
+
+ elif options['chemfig_command']:
+ output_list.insert(0, r'\chemfig{')
+ output_list.append(r'}')
+
+ if options['terse']:
+ output_list = strip_output(output_list)
+ joiner = '%\n'
+ else:
+ joiner = '\n'
+
+ return joiner.join(output_list)
diff --git a/graphics/mol2chemfig/install/mol2chemfig-1.5/src/common.py b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/common.py
new file mode 100644
index 0000000000..6957775c8e
--- /dev/null
+++ b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/common.py
@@ -0,0 +1,109 @@
+'''
+common settings and a bit of infrastructure
+'''
+import sys
+from options import getParser
+
+_debug = False
+
+#_debug_file = sys.stderr
+if _debug:
+ _debug_file = open('/data/code/mol2chemfig/bugs/dbg','w')
+
+program_version = '1.5'
+
+
+def debug(*args):
+ if not _debug:
+ return
+ args = [str(a) for a in args]
+ print >> _debug_file, " ".join(args)
+
+class MCFError(Exception):
+ '''
+ this flags an anticipated error due to faulty user input.
+ '''
+ pass
+
+# pubchem url for retrieving sdf for numerical IDs
+pubchem_url = r"http://pubchem.ncbi.nlm.nih.gov/summary/summary.cgi?cid=%s&disopt=DisplaySDF"
+
+_version_blurb = '''
+%(progname)s version %(version)s
+
+mol2chemfig generates chemfig code from molfiles.
+For more information, type '%(progname)s --help'.
+'''
+
+_lua_version_blurb = '''
+This is version %(client_version)s of %(progname)s,
+the Lua web client for the mol2chemfig server. The
+server is running version %(server_version)s of mol2chemfig;
+server and client version may differ.
+
+%(progname)s generates chemfig code from molfiles.
+For more information, type '%(progname)s --help'.
+'''
+
+def version_text(progname='mol2chemfig', version=program_version):
+ return _version_blurb % locals()
+
+_help_blurb = '''\
+%(progname)s v. %(version)s, by Eric Brefo-Mensah and Michael Palmer
+%(progname)s generates chemfig code from molfiles. Usage example:
+
+%(progname)s --angle=45 --aromatic-circles somefile.mol
+
+Options:
+'''
+
+def help_text(progname="mol2chemfig", version=program_version):
+ msg = _help_blurb % locals()
+ msg += getParser().format_help(indent=32, linewidth=75, separator='')
+
+ return msg
+
+def lua_version_text(progname, client_version):
+ server_version = program_version
+ return _lua_version_blurb % locals()
+
+# the settings dict contains a number of fixed settings that can not
+# be overridden from the command line. A copy of this dict will
+# augmented with command line options and passed around during processing.
+
+settings = dict(
+ # input mode: auto, molfile, molblock, smilesfile, smiles
+ input_mode = 'auto',
+
+ # use relative angles
+ relative_angles = False,
+
+ # round bond lengths to this many decimal digits
+ bond_round = 3,
+
+ # round angles to this many digits
+ angle_round = 1,
+
+ # tolerance for angle impingement on atom quadrants, range 0 to 1
+ quadrant_tolerance = 0.1,
+)
+
+class Counter(object):
+ '''
+ a simple Counter class, just to remove the dependency on version 2.7
+ (which provides one in module collections)
+ '''
+ def __init__(self, lst):
+ self._d = {}
+
+ for val in lst:
+ if not val in self._d:
+ self._d[val] = 0
+
+ self._d[val] += 1
+
+ def most_common(self):
+ lst = self._d.items()
+ lst.sort(key=lambda pair: pair[1])
+
+ return lst[-1][0]
diff --git a/graphics/mol2chemfig/install/mol2chemfig-1.5/src/molecule.py b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/molecule.py
new file mode 100644
index 0000000000..9c5a48b491
--- /dev/null
+++ b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/molecule.py
@@ -0,0 +1,702 @@
+'''
+parse a molfile molecule and render to chemfig code
+'''
+
+import math, sys
+
+import chemfig_mappings as cfm
+from common import MCFError, Counter, debug
+
+from atom import Atom
+from bond import Bond, DummyFirstBond, AromaticRingBond, compare_positions
+
+from indigo import IndigoException
+
+class Molecule(object):
+
+ bond_scale = 1.0 # can be overridden by user option
+ exit_bond = None # the first bond in the tree that connects to the exit atom
+
+ def __init__(self, options, tkmol):
+ self.options = options
+ self.tkmol = tkmol
+
+ self.atoms = self.parseAtoms()
+
+ # now it's time to flip and flop the coordinates
+ for atom in self.atoms.values():
+ if self.options['flip_horizontal']:
+ atom.x = -atom.x
+ if self.options['flip_vertical']:
+ atom.y = -atom.y
+
+ self.bonds, self.atom_pairs = self.parseBonds()
+
+ # work out the angles for each atom - this is used for
+ # positioning of implicit hydrogens and charges.
+
+ for connection, bond in self.bonds.items():
+ first_idx, last_idx = connection
+ self.atoms[first_idx].bond_angles.append(bond.angle)
+
+ # this would be the place to work out the placement of the second
+ # and third strokes.
+
+ # connect fragments, if any, with invisible bonds. By doing this
+ # AFTER assigning bond angles, we prevent these invisible bonds
+ # from interfering with placement of hydrogens or charges.
+ self.connect_fragments() # connect fragments or isolated atoms
+
+ # arrange the bonds into a tree
+ self.seen_atoms = set()
+ self.seen_bonds = set()
+
+ self.entry_atom, self.exit_atom = self.pickFirstLastAtoms()
+ self.root = self.parseTree(start_atom=None, end_atom=self.entry_atom)
+
+
+ if len(self.atoms) > 1:
+ if self.exit_atom is None: # pick a default exit atom if needed
+ self.exit_bond = self.default_exit_bond()
+ self.exit_atom = self.exit_bond.end_atom
+
+ # flag all atoms between the entry atom and the exit atom - these
+ # will be part of the trunk, all others will be rendered as branches
+ if self.entry_atom is not self.exit_atom:
+ flagged_bond = self.exit_bond
+
+ while flagged_bond.end_atom is not self.entry_atom:
+ flagged_bond.is_trunk = True
+ flagged_bond = flagged_bond.parent
+
+ # process cross bonds
+ if self.options['cross_bond'] is not None:
+ self.process_cross_bonds()
+
+ # adjust bond lengths
+ self.scaleBonds()
+
+ # modify bonds in rings
+ self.annotateRings()
+
+ # let each atom work out its preferred quadrant for placing
+ # hydrogens or charges
+ for atom in self.atoms.values():
+ atom.score_angles()
+
+ # finally, render the thing and cache the result.
+ self._rendered = self.render()
+
+
+ def link_atoms(self, x, y):
+ '''
+ connect atoms with indexes x and y using a pseudo bond.
+ Helper for connect_fragments
+ '''
+ start_atom = self.atoms[x]
+ end_atom = self.atoms[y]
+
+ bond = Bond(self.options, start_atom, end_atom)
+ bond.set_link()
+
+ self.bonds[(x, y)] = bond
+ self.bonds[(y, x)] = bond.invert()
+
+ start_atom.neighbors.append(y)
+ end_atom.neighbors.append(x)
+
+
+ def connect_fragments(self):
+ '''
+ connect multiple fragments, using link bonds across their
+ last and first atoms, respectively.
+ '''
+ fragments = self.molecule_fragments()
+
+ if len(fragments) > 1:
+
+ for head, tail in zip(fragments[:-1], fragments[1:]):
+ head_last = head[-1][-1]
+ tail_first = tail[0][0]
+
+ self.link_atoms(head_last, tail_first)
+
+ # now look for orphaned single atoms
+ atoms = set(self.atoms.keys())
+
+ bonded = set()
+ for pair in self.atom_pairs:
+ bonded.update(pair)
+
+ unbonded = list(atoms - bonded)
+
+ if unbonded:
+ if fragments:
+ anchor = fragments[-1][-1][-1]
+ else: # several atoms, but no bonds
+ anchor, unbonded = unbonded[0], unbonded[1:]
+
+ for atom in unbonded:
+ self.link_atoms(anchor, atom)
+
+
+ def molecule_fragments(self):
+ '''
+ identify unconnected fragments in the molecule.
+ used by connect_fragments
+
+ indigo actually has its own API method for extracting fragments.
+ '''
+ def split_pairs(pair_list):
+ '''
+ break up pair_list into one list that contains all pairs
+ that are connected, directly or indirectly, to the first
+ pair in the list, and another list containing the rest.
+ '''
+ first, rest = pair_list[0], pair_list[1:]
+ connected_atoms = set(first)
+
+ connected_pairs = [first]
+
+ while True:
+ unconnected = []
+
+ for r in rest:
+ s = set(r)
+
+ if connected_atoms & s:
+ connected_atoms |= s
+ connected_pairs.append(r)
+ else:
+ unconnected.append(r)
+
+ if len(unconnected) == len(rest): # no new pairs found in this loop iteration
+ return connected_pairs, unconnected
+ else:
+ rest = unconnected
+
+ fragments = []
+
+ atom_pairs = self.atom_pairs[:]
+
+ if len(atom_pairs) == 0:
+ return []
+ elif len(atom_pairs) == 1:
+ return [atom_pairs]
+
+ while True:
+ connected, rest = split_pairs(atom_pairs)
+ fragments.append(connected)
+
+ if not rest:
+ return fragments
+ else:
+ atom_pairs = rest
+
+
+ def treebonds(self,root=False):
+ '''
+ return a list with all bonds in the molecule tree
+ '''
+ allbonds = []
+
+ def recurse(rt):
+ allbonds.append(rt)
+
+ for d in rt.descendants:
+ recurse(d)
+
+ recurse(self.root)
+
+ if not root:
+ allbonds = allbonds[1:]
+
+ return allbonds
+
+
+ def process_cross_bonds(self):
+ '''
+ if cross bonds have been declared:
+ 1. tag the corresponding bonds within the tree as no-ops
+ 2. create a ghost-bond connection from exit_atom to start atom
+ 3. create a drawn duplicate of the cross bond
+ 4. append 2 and 3 as branch to the exit atom
+
+ this is unfortunately all a little hackish.
+ '''
+ cross_bonds = self.options['cross_bond']
+
+ for start1, end1 in cross_bonds:
+ start = start1 - 1
+ end = end1 - 1
+
+ # retrieve the matching bond that's in the parse tree
+ for combo in ((start, end), (end, start)):
+ if combo in self.seen_bonds:
+ bond = self.bonds[combo]
+ break
+ else: # referenced bond doesn't exist
+ raise MCFError, "bond %s-%s doesn't exist" % (start1, end1)
+
+ # very special case: the bond _might_ already be the very
+ # last one to be rendered - then we just tag it
+ if self.exit_bond.descendants and bond is self.exit_bond.descendants[-1]:
+ bond.set_cross(last=True)
+ continue
+
+ # create a copy of the bond that will be rendered later
+ bond_copy = bond.clone()
+
+ # tag original bond as no-op
+ bond.set_link()
+
+ # modify bond copy
+ bond_copy.set_cross()
+ bond_copy.to_phantom = True # don't render atom again
+ bond_copy.descendants = [] # forget copied descendants
+
+ if bond_copy.start_atom is not self.exit_atom: # usual case
+ # create a pseudo bond from the exit atom to the start atom
+ # pseudo bond will not be drawn, serves only to "move the pen"
+ pseudo_bond = Bond(self.options,
+ self.exit_atom,
+ bond_copy.start_atom)
+
+ pseudo_bond.set_link()
+ pseudo_bond.to_phantom = True # don't render the atom, either
+
+ bond_copy.parent = pseudo_bond
+ pseudo_bond.descendants.append(bond_copy)
+
+ pseudo_bond.parent = self.exit_bond
+ self.exit_bond.descendants.append(pseudo_bond)
+
+ else: # occasionally, the molecule's exit atom may be the starting point
+ # of the elevated bond
+ self.exit_bond.descendants.append(bond_copy)
+
+
+ def default_exit_bond(self):
+ '''
+ pick the bond and atom that is at the greatest distance from
+ the entry atom along the parsed molecule tree. This
+ must be one of the leaf atoms, obviously.
+ '''
+ scored = []
+
+ for bond in self.treebonds():
+ if bond.to_phantom: # don't pick phantom atoms as exit
+ continue
+
+ distance = 0
+
+ the_bond = bond
+
+ while the_bond is not None and the_bond.end_atom is not self.entry_atom:
+ distance += 1
+ the_bond = the_bond.parent
+
+ scored.append((distance, len(bond.descendants), bond))
+
+ scored.sort()
+ return scored[-1][-1]
+
+
+ def pickFirstLastAtoms(self):
+ '''
+ If the first atom is not given, we try to pick one
+ that has only one bond to the rest of the molecule,
+ so that only the first angle is absolute.
+ '''
+ if self.options['entry_atom'] is not None:
+ entry_atom = self.atoms.get(self.options['entry_atom'] - 1) # -> zero index
+ if entry_atom is None:
+ raise MCFError, 'Invalid entry atom number'
+
+ else: # pick a default atom with few neighbors
+ atoms = self.atoms.values()
+ atoms.sort(key=lambda atom: len(atom.neighbors))
+ entry_atom = atoms[0]
+
+ if self.options['exit_atom'] is not None:
+ exit_atom = self.atoms.get(self.options['exit_atom'] - 1) # -> zero index
+ if exit_atom is None:
+ raise MCFError, 'Invalid exit atom number'
+ else:
+ exit_atom = None
+
+ return entry_atom, exit_atom
+
+
+ def parseAtoms(self):
+ '''
+ Read some attributes from the toolkit atom object
+ '''
+ coordinates = []
+
+ # wrap all atoms and supply coordinates
+ wrapped_atoms = {}
+
+ for ra in self.tkmol.iterateAtoms():
+ idx = ra.index()
+ element = ra.symbol()
+
+ try:
+ hydrogens = ra.countImplicitHydrogens()
+ except IndigoException:
+ if self.options['strict']:
+ raise
+ hydrogens = 0
+
+ charge = ra.charge()
+ radical = ra.radicalElectrons()
+
+ neighbors = [na.index() for na in ra.iterateNeighbors()]
+
+ x, y, z = ra.xyz()
+
+ wrapped_atoms[idx] = Atom(self.options,
+ idx,
+ x, y,
+ element,
+ hydrogens,
+ charge,
+ radical,
+ neighbors)
+
+ return wrapped_atoms
+
+
+ def parseBonds(self):
+ '''
+ read some bond attributes
+ '''
+ bonds = {} # dictionary with bond objects, both orientations
+ atom_pairs = [] # atom index pairs only, unique
+
+ for bond in self.tkmol.iterateBonds():
+ # start, end, bond_type, stereo = numbers
+ start = bond.source().index()
+ end = bond.destination().index()
+
+ bond_type = bond.bondOrder() # 1,2,3,4 for single, double, triple, aromatic
+ stereo = bond.bondStereo()
+
+ start_atom = self.atoms[start]
+ end_atom = self.atoms[end]
+
+ bond = Bond(self.options, start_atom, end_atom, bond_type, stereo)
+
+ # we store both orientations of the bond, since we don't know yet
+ # which way it will be used
+ bonds[(start, end)] = bond
+ bonds[(end, start)] = bond.invert()
+
+ atom_pairs.append((start, end))
+
+ return bonds, atom_pairs
+
+
+ def parseTree(self, start_atom, end_atom):
+ '''
+ recurse over atoms in molecule to create a tree of bonds
+ '''
+ end_idx = end_atom.idx
+
+ if start_atom is None: # this is the first atom in the molecule
+ bond = DummyFirstBond(self.options, end_atom=end_atom)
+
+ else:
+ start_idx = start_atom.idx
+
+ # guard against reentrant bonds. Can those even still happen?
+ # apparently they can, even if I don't really understand how.
+ if (start_idx, end_idx) in self.seen_bonds or \
+ (end_idx, start_idx) in self.seen_bonds:
+
+ return None
+
+ # if we get here, the bond is not in the tree yet
+ bond = self.bonds[(start_idx, end_idx)]
+
+ # flag it as known
+ self.seen_bonds.add((start_idx, end_idx))
+
+ # detect bonds that close rings, and tell them render
+ # with phantom atoms
+ if end_idx in self.seen_atoms:
+ bond.to_phantom = True
+ return bond
+
+ # flag end atom as known
+ self.seen_atoms.add(end_idx)
+
+ if end_atom is self.exit_atom:
+ self.exit_bond = bond
+
+ # recurse over the neighbors of the end atom
+ for ni in end_atom.neighbors:
+ if start_atom and ni == start_idx: # don't recurse backwards
+ continue
+
+ next_atom = self.atoms[ni]
+ next_bond = self.parseTree(end_atom, next_atom)
+
+ if next_bond is not None:
+ next_bond.parent = bond
+ bond.descendants.append(next_bond)
+
+ return bond
+
+
+ def _getBond(self, tkbond):
+ '''
+ helper for aromatizeRing: find bond in parse tree that
+ corresponds to toolkit bond
+ '''
+ start_idx = tkbond.source().index()
+ end_idx = tkbond.destination().index()
+
+ if (start_idx, end_idx) in self.seen_bonds:
+ return self.bonds[(start_idx, end_idx)]
+
+ # the bond must be going the other way ...
+ return self.bonds[(end_idx, start_idx)]
+
+
+ def aromatizeRing(self, ring, center_x, center_y):
+ '''
+ render a ring that is aromatic and is a regular polygon
+ '''
+ # first, set all bonds to aromatic
+ ringbonds = list(ring.iterateBonds())
+
+ for tkbond in ringbonds:
+ bond = self._getBond(tkbond)
+ bond.bond_type = 'aromatic'
+
+ # any bond can serve as the anchor for the circle,
+ # so we'll just use the last one from the loop
+ atom = bond.end_atom
+
+ outer_r, angle = compare_positions(atom.x, atom.y, center_x, center_y)
+ # angle is based on raw coordinates - adjust for user-set rotation
+ angle += self.options['rotate']
+
+ # outer_r calculated from raw coordinates, must be adjusted
+ # for bond scaling that may have taken place
+ outer_r *= self.bond_scale
+
+ alpha = ( math.pi / 2 - math.pi / len(ringbonds) )
+ inner_r = math.sin(alpha) * outer_r
+
+ arb = AromaticRingBond(self.options, bond, angle, outer_r, inner_r)
+ bond.descendants.append(arb)
+
+
+ def annotateRing(self, ring, is_aromatic):
+ '''
+ determine center, symmetry and aromatic character of ring
+ I wonder if indigo would tell us directly about these ...
+
+ annotate double bonds in rings, or alternatively decorate
+ ring with aromatic circle.
+ '''
+ atoms = set()
+ bond_lengths = []
+ bonds = []
+
+
+ for tkbond in ring.iterateBonds():
+ bond = self._getBond(tkbond)
+ bonds.append(bond)
+
+ atoms.add(self.atoms[bond.start_atom.idx])
+ atoms.add(self.atoms[bond.end_atom.idx])
+ bond_lengths.append(bond.length)
+
+ if len(bonds) > 8: # large rings may foul things up, so we skip them.
+ return
+
+ bl_max = max(bond_lengths)
+ bl_spread = (bl_max - min(bond_lengths)) / bl_max
+
+ # determine ring center
+ center_x = sum([atom.x for atom in atoms]) / len(atoms)
+ center_y = sum([atom.y for atom in atoms]) / len(atoms)
+
+ # compare distances from center. Also remember atoms and bond
+ # angles; if the ring ends up being aromatized, we flag those
+ # angles as occupied (by the fancy circle inside the ring).
+ atom_angles = []
+ center_distances = []
+
+ for atom in atoms:
+ length, angle = compare_positions(atom.x, atom.y, center_x, center_y)
+ center_distances.append(length)
+ atom_angles.append((atom, angle))
+
+ cd_max = max(center_distances)
+ cd_spread = (cd_max - min(center_distances)) / cd_max
+
+ tolerance = 0.05
+ is_symmetric = (cd_spread <= tolerance and bl_spread <= tolerance)
+
+ if is_aromatic and is_symmetric and self.options['aromatic_circles']:
+ # ring meets all requirements to be displayed with circle inside
+ self.aromatizeRing(ring, center_x, center_y)
+ # flag bond angles as occupied
+ for atom, angle in atom_angles:
+ atom.bond_angles.append(angle)
+
+ else: # flag orientation individual bonds - will influence
+ # rendering of double bonds
+ for bond in bonds:
+ bond.is_clockwise(center_x, center_y)
+
+
+ def annotateRings(self):
+ '''
+ modify double bonds in rings. In aromatic rings, we optionally
+ do away with double bonds altogether and draw a circle instead
+ '''
+ self.tkmol.aromatize()
+
+ all_rings = []
+
+ for ring in self.tkmol.iterateSSSR():
+ # bond-order == 4 means "aromatic"; all rings bonds must be aromatic
+ is_aromatic = all(bond.bondOrder() == 4 for bond in ring.iterateBonds())
+ all_rings.append((is_aromatic, ring))
+
+ # prefer aromatic rings to nonaromatic ones, so that double bonds on
+ # fused rings go preferably into aromatic rings
+ all_rings.sort()
+
+ for is_aromatic, ring in reversed(all_rings):
+ self.annotateRing(ring, is_aromatic)
+
+
+ def scaleBonds(self):
+ '''
+ scale bonds according to user options
+ '''
+ if self.options['bond_scale'] == 'keep':
+ pass
+
+ elif self.options['bond_scale'] == 'normalize':
+ lengths = [bond.length for bond in self.treebonds()]
+ lengths = [round(l, self.options['bond_round']) for l in lengths]
+ lengths = Counter(lengths)
+ self.bond_scale = self.options['bond_stretch'] / lengths.most_common()
+
+ elif self.options['bond_scale'] == 'scale':
+ self.bond_scale = self.options['bond_stretch']
+
+ for bond in self.treebonds():
+ bond.length = self.bond_scale * bond.length
+
+
+ def render(self):
+ '''
+ render molecule to chemfig
+ '''
+ output = []
+ self._render(output, bond=self.root, level=0)
+
+ return output
+
+
+ def render_user(self):
+ '''
+ returns code formatted according to user options
+ '''
+ return cfm.format_output(self.options, self._rendered)
+
+
+ def render_server(self):
+ '''
+ returns code formatted for server-side PDF generation
+ '''
+ # override some options
+ params = dict(self.options)
+ params['submol_name'] = None
+ # params['terse'] = False # why?
+ params['chemfig_command'] = True
+
+ return cfm.format_output(params, self._rendered)
+
+
+ def _renderBranches(self, output, level, bonds):
+ '''
+ render a list of branching bonds indented and inside enclosing brackets.
+ '''
+ branch_indent = self.options['indent']
+
+ for bond in bonds:
+ output.append("(".rjust(level * branch_indent + cfm.BOND_CODE_WIDTH))
+ self._render(output, bond, level)
+ output.append(")".rjust(level * branch_indent + cfm.BOND_CODE_WIDTH))
+
+
+ def _render(self, output, bond, level):
+ '''
+ recursively render the molecule.
+ '''
+ output.append(bond.render(level))
+ branches = bond.descendants
+
+ if bond is self.exit_bond: # wrap all downstream bonds in branch
+ self._renderBranches(output, level+1, branches)
+
+ elif branches: # prioritize bonds on the trunk from entry to exit
+ for i, branch in enumerate(branches):
+ if branch.is_trunk:
+ first = branches.pop(i)
+ break
+ else:
+ first = branches.pop(0)
+
+ self._renderBranches(output, level+1, branches)
+ self._render(output, first, level)
+
+
+ def dimensions(self):
+ '''
+ this calculates the approximate width and height
+ of the rendered molecule, in units of chemfig
+ standard bond length (multiply with chemfig's
+ \setatomsep parameter to obtain the physical size).
+
+ It is only used for server side PDF generation,
+ but maybe someone will have another use for it.
+ '''
+ minx = maxx = miny = maxy = None
+
+ alpha = self.options['rotate']
+ alpha *= math.pi/180
+
+ sinalpha = math.sin(alpha)
+ cosalpha = math.cos(alpha)
+
+ for atom in self.atoms.values():
+ x, y = atom.x, atom.y
+
+ xt = x * cosalpha - y * sinalpha
+ yt = x * sinalpha + y * cosalpha
+
+ if minx is None or xt < minx:
+ minx = xt
+ if maxx is None or xt > maxx:
+ maxx = xt
+ if miny is None or yt < miny:
+ miny = yt
+ if maxy is None or yt > maxy:
+ maxy = yt
+
+ xsize = (maxx - minx) * self.bond_scale
+ ysize = (maxy - miny) * self.bond_scale
+
+ return xsize, ysize
+
+
diff --git a/graphics/mol2chemfig/install/mol2chemfig-1.5/src/optionparser.py b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/optionparser.py
new file mode 100644
index 0000000000..5fc48d3d80
--- /dev/null
+++ b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/optionparser.py
@@ -0,0 +1,458 @@
+'''
+parsing options with a nicer wrapper around getopt.
+Still throws getopt.GetoptError at runtime.
+
+Let's try to combine this with basic html form
+parsing, so that we can declare the options just
+once.
+
+Can we make this a bit more elegant by using
+class attributes and more subclassing than
+instantiation? The problem then is, of course,
+that client code will have to do both.
+'''
+
+import getopt, textwrap, re
+
+class OptionError(Exception):
+ pass
+
+class Option(object):
+ collapseWs = re.compile('\s+')
+
+ form_tag_template = "<!-- Option class needs to define a valid form tag template -->"
+
+ def __init__(self,
+ long_name,
+ short_name,
+ form_text=None,
+ key=None,
+ default=None,
+ valid_range=None,
+ help_text="""Our engineers deemed
+ it self-explanatory"""):
+
+ self.long_name = long_name
+ self.short_name = short_name
+ self.key = key or long_name
+ self.form_text = form_text or long_name
+
+ self.valid_range = valid_range # must precede assignment of self.default
+
+ if default is None:
+ default = self._default()
+ self.default = self.value = default
+
+ self.help_text = help_text
+
+
+ def _default(self):
+ return None
+
+
+ def validate_range(self, value):
+ '''
+ can be overridden if more general tests are needed
+ '''
+ return self.valid_range is None or value in self.valid_range
+
+
+ def validate(self, value):
+ success, converted = self._validate(value)
+ success = success and self.validate_range(converted)
+
+ if success:
+ self.value = converted
+ return True
+ return False
+
+
+ def validate_form_value(self, value):
+ '''
+ validation of option value received through a
+ web form. May need to be different from CLI,
+ but by default it's not.
+ '''
+ return self.validate(value)
+
+
+ def _validate(self, value):
+ '''
+ no-op default
+ '''
+ return True, value
+
+
+ def short_getopt(self):
+ '''
+ short option template for getopt
+ '''
+ return self.short_name + ':'
+
+
+ def long_getopt(self):
+ '''
+ long option template for getopt
+ '''
+ return self.long_name + '='
+
+
+ def format_help(self, indent=30, linewidth=80):
+ '''
+ format option and help text for console display
+ maybe we can generalize this for html somehow
+ '''
+ help_text = '%s (Default: %s)' % (self.help_text, self.default)
+ help_text = self.collapseWs.sub(' ', help_text.strip())
+
+ hwrap = textwrap.wrap(help_text,
+ width = linewidth,
+ initial_indent=' ' * indent,
+ subsequent_indent= ' ' * indent)
+
+ opts = '-%s, --%s' % (self.short_name, self.long_name)
+ hwrap[0] = opts.ljust(indent) + hwrap[0].lstrip()
+
+ return hwrap
+
+
+ def format_tag_value(self, value):
+ '''
+ format the default value for insertion into form tag
+ '''
+ if value is None:
+ return ''
+ return str(value)
+
+
+ def format_tag(self, value=None):
+ '''
+ render a html form tag
+ '''
+ value = value or self.default
+
+ values = dict(key=self.key, value=self.format_tag_value(value) )
+ tag = self.form_tag_template % values
+
+ return self.key, tag, self.form_text, self.help_text
+
+
+
+class BoolOption(Option):
+
+ form_tag_template = r'''<input type="checkbox" name="%(key)s" value="yes" %(value)s/>'''
+
+ def _default(self):
+ return False
+
+
+ def validate(self, value=None):
+ '''
+ value should be empty; we accept and discard it.
+ we simply switch the default value.
+ '''
+ self.value = not self.default
+ return True
+
+
+ def validate_form_value(self, value):
+ '''
+ if a value arrives through a web form, the box has been
+ ticked, so we set to True regardless of default. The passed
+ value itself is unimportant.
+ '''
+ self.value = True
+ return True
+
+
+ def short_getopt(self):
+ return self.short_name
+
+
+ def long_getopt(self):
+ return self.long_name
+
+
+ def format_tag_value(self, value):
+ if value is True:
+ return 'checked="checked"'
+ else:
+ return ''
+
+
+class SelectOption(Option):
+ '''
+ make a selection from a list of valid string values.
+ argument valid_range cannot be empty with this class.
+ '''
+ option_template = r'''<option value="%(option)s" %(selected)s>%(option)s</option>'''
+ field_template = '''<select name="%(key)s">\n%(options)s\n</select>'''
+
+ def _default(self):
+ '''
+ we stipulate that valid_range is not empty.
+ '''
+ try:
+ return self.valid_range[0]
+ except (TypeError, IndexError):
+ raise OptionError, 'valid_range does not supply default'
+
+
+ def _validate(self, value):
+ ''''
+ we enforce conversion to lowercase
+ '''
+ return True, value.lower()
+
+
+ def format_tag(self, value=None):
+
+ value = value or self.default
+
+ options = []
+
+ if not self.default in self.valid_range: # why am I doing this here?
+ raise OptionError, 'invalid default'
+
+ for option in self.valid_range:
+ if option == value:
+ selected = 'selected="selected"'
+ else:
+ selected = ''
+ options.append(self.option_template % dict(option=option, selected=selected))
+
+ option_string = '\n'.join(options)
+
+ tag = self.field_template % dict(options = option_string, key=self.key)
+ return self.key, tag, self.form_text, self.help_text
+
+
+class TypeOption(Option):
+ '''
+ coerces an input value to a type
+ '''
+ _type = int # example
+ _class_default = 0
+
+ form_tag_template = r'''<input type="text" name="%(key)s" value="%(value)s" size="8"/>'''
+
+ def _validate(self, value):
+ try:
+ converted = self._type(value)
+ return True, converted
+ except ValueError:
+ return False, value
+
+
+
+class IntOption(TypeOption):
+ _type = int
+
+
+class FloatOption(TypeOption):
+ _type = float
+
+
+class StringOption(TypeOption):
+ _type = str
+
+
+class RangeOption(Option):
+ '''
+ accept a string that can be parsed into one or more int ranges,
+ such as 5-6,7-19
+ these should be converted into [(5,6),(7,19)]
+ '''
+ outersep = ','
+ innersep = '-'
+ form_tag_template = r'''<input type="text" name="%(key)s" value="%(value)s" size="8"/>'''
+
+ def _validate(self, rawvalue):
+ ranges = []
+ outerfrags = rawvalue.split(self.outersep)
+
+ for frag in outerfrags:
+ innerfrags = frag.split(self.innersep)
+ if len(innerfrags) != 2:
+ return False, rawvalue
+ try:
+ ranges.append((int(innerfrags[0]), int(innerfrags[1])))
+ except ValueError:
+ return False, rawvalue
+
+ return True, ranges
+
+
+class OptionParser(object):
+ '''
+ collect and process options. the result will be contained in a dict.
+ '''
+ def __init__(self):
+ self._options = []
+ self._options_by_name = {}
+ self._options_by_key = {}
+
+
+ def append(self, option):
+ if option.short_name in self._options_by_name:
+ raise OptionError, "option name clash %s" % option.short_name
+ if option.long_name in self._options_by_name:
+ raise OptionError, "option name clash %s" % option_short_name
+
+ self._options_by_name[option.short_name] = option.key
+ self._options_by_name[option.long_name] = option.key
+ self._options_by_key[option.key] = option
+
+ # also maintain options ordered in a list
+ self._options.append(option)
+
+
+ def validKeys(self):
+ '''
+ required by the web form front end
+ '''
+ return self._option_by_key.keys()
+
+
+ def option_values(self):
+ '''
+ read current option values
+ '''
+ option_dict = {}
+
+ for option in self._options:
+ option_dict[option.key] = option.value
+
+ return option_dict
+
+
+ def process_form_fields(self, fields):
+ '''
+ process options received through the web form.
+ we don't look at the cargo data here at all.
+
+ what do we do about invalid options? puke? ignore?
+ create a list of warnings and then ignore.
+ '''
+ warnings = []
+
+ for key, value in fields.items():
+ option = self._options_by_key[key]
+ if not option.validate_form_value(value):
+ msg = 'Invalid value %s for option %s ignored' % (value, option.form_text)
+ warnings.append(msg)
+
+ return self.option_values(), warnings
+
+
+ def process_cli(self, rawinput):
+ '''
+ process input from the command line interface
+ - assemble template strings for getopt and run getopt
+ - pass the result back to each option
+ '''
+ try: # accept lists or strings
+ rawinput = rawinput.strip().split()
+ except AttributeError:
+ pass
+
+ shorts, longs = self.format_for_getopt()
+
+ opts, args = getopt.getopt(rawinput, shorts, longs)
+
+ for optname, value in opts:
+ key = self._options_by_name[optname.lstrip('-')]
+ option = self._options_by_key[key]
+
+ if not option.validate(value):
+ msg = ["rejected value '%s' for option %s" % (value, optname)]
+ msg.append('Option usage:')
+ msg.extend(option.format_help())
+ raise OptionError, '\n'.join(msg)
+
+ return self.option_values(), args
+
+
+ def format_for_getopt(self):
+ shorts = ''.join([option.short_getopt() for option in self._options])
+ longs = [option.long_getopt() for option in self._options]
+
+ return shorts, longs
+
+
+ def format_for_lua(self):
+ '''
+ with lua, we use dumb option parsing. we only provide enough
+ information for lua to distinguish between options with and
+ without arguments.
+ '''
+ bools = [opt for opt in self._options if isinstance(opt, BoolOption)]
+ shorts = [nb.short_name for nb in bools]
+ return ''.join(shorts)
+
+
+ def format_help(self, indent=25, linewidth=70, separator=None):
+ '''
+ just ask the options to render themselves
+ '''
+ output = []
+
+ for option in self._options:
+ output.extend(option.format_help(indent, linewidth))
+
+ if separator is not None:
+ output.append(separator)
+
+ return '\n'.join(output)
+
+
+ def form_tags(self):
+ '''
+ collect the html for each option
+ '''
+ return [opt.format_tag() for opt in self._options]
+
+
+if __name__ == '__main__': # test it
+
+ p = OptionParser()
+
+ p.append(BoolOption(
+ 'absolute',
+ 'a',
+ # default=True,
+ help_text = 'not relative. what happens if we choose to use a really, really, really excessively long help text here?'))
+
+ p.append(IntOption(
+ 'count',
+ 'c',
+ default=5,
+ valid_range=range(10),
+ help_text="how many apples to buy"))
+
+ p.append(StringOption(
+ 'party',
+ 'p',
+ default="NDP",
+ help_text="what party to choose"))
+
+ p.append(FloatOption(
+ 'diameter',
+ 'd',
+ default=3.14,
+ help_text='how big it is'))
+
+ p.append(StringOption(
+ 'candy',
+ 'n',
+ default='chocolate'))
+
+
+ rawinput = "-a -c 6 -p LP alpha beta gamma"
+ options, args = p.process_cli(rawinput)
+
+ print 'options', options
+ print 'args', args
+ print
+ print p.format_help()
+ print p.form_tags()
diff --git a/graphics/mol2chemfig/install/mol2chemfig-1.5/src/options.py b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/options.py
new file mode 100644
index 0000000000..ebb733386f
--- /dev/null
+++ b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/options.py
@@ -0,0 +1,236 @@
+'''
+option declarations. The options will be used to update the
+settings dict in module common.
+'''
+from optionparser import *
+
+def getParser():
+ '''
+ make sure the parser is created anew on each request
+ '''
+
+ parser = OptionParser()
+
+ parser.append(BoolOption(
+ "help",
+ "h",
+ default=False,
+ help_text="Print help message and exit"))
+
+ parser.append(BoolOption(
+ "version",
+ "b",
+ default=False,
+ help_text="Print program version and exit"))
+
+ parser.append(SelectOption(
+ "input",
+ "i",
+ key="input",
+ default="file",
+ valid_range="direct file pubchem".split(),
+ help_text="""How to interpret the argument. With 'file', mol2chemfig
+ expects a filename. With 'direct', the argument is
+ intrepreted directly; don't forget to put quotes around
+ it. With 'pubchem', the argument is treated as an
+ identifier for the PubChem database."""))
+
+ parser.append(BoolOption(
+ "terse",
+ "z",
+ default=False,
+ help_text="""Remove all whitespace and comments from the output.
+ If you can still read it afterwards, Bill Gates
+ wants your resume"""))
+
+ parser.append(BoolOption(
+ "strict",
+ "r",
+ default=True,
+ help_text="""Abide by Indigo's chemical structure validation.
+ If true, mol2chemfig will fail if Indigo reports
+ that something is wrong with the molecule, like
+ a carbon with five bonds. If false, mol2chemfig
+ will ignore such errors"""))
+
+
+ parser.append(IntOption(
+ "indent",
+ "d",
+ default=4,
+ help_text="""Number of spaces to use for indenting molecule
+ branches in generated code. Without effect when
+ 'terse' option is passed. Affects only the generated
+ tex code, not the rendered molecule"""))
+
+ parser.append(BoolOption(
+ "recalculate-coordinates",
+ "u",
+ key="recalculate_coordinates",
+ help_text="""Discard existing coordinate and calculate new
+ ones from covalent structure. For smiles input,
+ this is performed implicitly"""))
+
+ parser.append(FloatOption(
+ "angle",
+ "a",
+ key="rotate",
+ default=0.0,
+ help_text="Rotate molecule counterclockwise by this angle"))
+
+ parser.append(BoolOption(
+ "relative-angles",
+ "v",
+ key="relative_angles",
+ default=False,
+ help_text="Use relative bond angles"))
+
+ parser.append(BoolOption(
+ "flip",
+ "p",
+ key="flip_horizontal",
+ default=False,
+ help_text="Flip the structure horizontally"))
+
+ parser.append(BoolOption(
+ "flop",
+ "q",
+ key="flip_vertical",
+ default=False,
+ help_text="Flip the structure vertically"))
+
+ parser.append(BoolOption(
+ "show-carbons",
+ "c",
+ key="show_carbons",
+ help_text="Show element symbol for carbon atoms"))
+
+ parser.append(BoolOption(
+ "show-methyls",
+ "m",
+ key="show_methyls",
+ help_text='''Show element symbols for methyl groups
+ (implied if show-carbons is True)'''))
+
+ parser.append(SelectOption(
+ "hydrogens",
+ "y",
+ key="hydrogens",
+ # default="keep",
+ valid_range="keep add delete".split(),
+ help_text="""How to deal with explicit hydrogen atoms.
+ One of 'keep', 'add' or 'delete'. Note that
+ 'add' will also trigger calculation of new
+ coordinates for the entire molecule.
+ Option 'keep' does nothing"""))
+
+ parser.append(BoolOption(
+ "aromatic-circles",
+ "o",
+ key="aromatic_circles",
+ default=False,
+ help_text="Draw circles instead of double bonds inside aromatic rings"))
+
+ parser.append(BoolOption(
+ "fancy-bonds",
+ "f",
+ key="fancy_bonds",
+ default=False,
+ help_text="Draw fancier double and triple bonds"))
+
+ parser.append(StringOption(
+ "markers",
+ "g",
+ help_text="""Give each atom and each bond a unique
+ marker that can be used for attaching
+ electron movement arrows.
+ With value 'a', atom 2 will be labeled
+ @{a2}, and its bond to atom 5 @{a2-5}."""))
+
+ parser.append(BoolOption(
+ "atom-numbers",
+ "n",
+ key="atom_numbers",
+ default=False,
+ help_text="""Show the molfile number of each atom next to it.
+ When this option is set, charges and implicit
+ hydrogens will not be shown"""))
+
+ parser.append(SelectOption(
+ "bond-scale",
+ "s",
+ key="bond_scale",
+ # default="normalize",
+ valid_range="normalize keep scale".split(),
+ help_text="""How to scale the lengths of bonds
+ (one of 'keep', 'scale', or 'normalize')"""))
+
+ parser.append(FloatOption(
+ "bond-stretch",
+ "t",
+ key="bond_stretch",
+ default=1.0,
+ help_text="""Used as scaling factor (with --bond-scale=scale)
+ or average (with --bond-scale=normalize) for bond
+ lengths"""))
+
+ parser.append(BoolOption(
+ "wrap-chemfig",
+ "w",
+ key="chemfig_command",
+ help_text=r"Wrap generated code into \chemfig{...} command"))
+
+ parser.append(StringOption(
+ "submol-name",
+ "l",
+ key="submol_name",
+ help_text=r"""If a name is given, wrap generated code into
+ chemfig \definesubmol{name}{...} command"""))
+
+ parser.append(IntOption(
+ "entry-atom",
+ "e",
+ key="entry_atom",
+ default=None,
+ help_text="""Number of first atom to be rendered. Relevant only
+ if generated code is to be used as sub-molecule"""))
+
+ parser.append(IntOption(
+ "exit-atom",
+ "x",
+ key="exit_atom",
+ default=None,
+ help_text="""Number of last atom to be rendered. Relevant only
+ if generated code is to be used as sub-molecule"""))
+
+ parser.append(RangeOption(
+ "cross-bond",
+ "k",
+ key="cross_bond",
+ default=None,
+ help_text="""Specify bonds that should be drawn on top of others
+ they cross over. Give the start and the end atoms.
+ Example for one bond: --cross-bond=5-6
+ Example for two bonds: --crossbond=4-8,12-13"""))
+
+ return parser
+
+
+if __name__ == '__main__': # test code
+ parser = getParser()
+ print parser.format_help(indent=32,linewidth=80,separator='')
+ print
+ shorts, longs = parser.format_for_getopt()
+ print longs
+ print shorts
+
+ # list unused option letters
+ from string import ascii_lowercase as letters
+ print "unused short options:", ','.join(set(letters) - set(shorts))
+
+ #print
+ #tags = parser.form_tags()
+ #print tags
+ #for tag in tags:
+ #print tag
+ #print
diff --git a/graphics/mol2chemfig/install/mol2chemfig-1.5/src/processor.py b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/processor.py
new file mode 100644
index 0000000000..6d83561820
--- /dev/null
+++ b/graphics/mol2chemfig/install/mol2chemfig-1.5/src/processor.py
@@ -0,0 +1,212 @@
+'''
+accept input from command line or through the web and
+return the result.
+'''
+
+import urllib, os.path, traceback
+from indigo import Indigo, IndigoException
+
+import common, options, molecule
+
+class HelpError(common.MCFError):
+ pass
+
+class Processor(object):
+ '''
+ parses input and invokes backend, returns result
+ '''
+ def __init__(self, rawargs, data, formfields, progname, webform, rpc):
+ self.rawargs = rawargs
+ self.data = data
+ self.formfields = formfields
+
+ # if the user renames the script file or the
+ # web client, use their new names
+ self.progname = os.path.split(progname)[-1]
+
+ # flags that indicate origin of input
+ self.webform = webform
+ self.rpc = rpc
+
+ self.optionparser = options.getParser()
+ self.options = dict(common.settings)
+
+ # data obtained from the proper source go here
+ self.data_string = None
+
+
+ def version_text(self):
+ '''
+ print the program version
+ '''
+ return common.version_text(progname=self.progname)
+
+
+ def help_text(self):
+ '''
+ error messages for the command line interface.
+ '''
+ return common.help_text(progname=self.progname)
+
+
+ def parseInputCli(self):
+ '''
+ parse input that came through the command line (locally or rpc)
+ return success flag and either error message or data
+ '''
+ # catch empty input
+ if not self.rawargs and not self.data:
+ ht = self.help_text()
+
+ raise HelpError, ht
+
+ # parse options and arguments
+ try:
+ parsed_options, datalist = self.optionparser.process_cli(self.rawargs)
+ except Exception, msg:
+ if str(msg).endswith('not recognized'): # getopt error
+ msg = str(msg) + \
+ ". Try %s --help to see a list of available options." % self.progname
+ raise HelpError, msg
+
+ # if we get here, we have parsed options and a possibly empty datalist
+ self.options.update(parsed_options)
+
+ # before we go on to check on the data, we will satisfy help requests,
+ # which we treat like an error
+ if self.options['help']:
+ raise HelpError, self.help_text()
+ elif self.options['version']:
+ raise HelpError, self.version_text()
+
+ if self.data is not None:
+ datalist.append(self.data)
+
+ # at this point, we should have reached the same state
+ # by rpc and local invocation
+
+ if len(datalist) != 1:
+ if not datalist:
+ raise common.MCFError, "No input data supplied"
+ raise common.MCFError, "Please give only one file or data string as input"
+
+ data = datalist[0]
+
+ if not self.rpc and self.options['input'] == 'file':
+ try:
+ data = open(data).read()
+ except IOError:
+ raise common.MCFError, "Can't read file %s" % data
+
+ self.data_string = data
+
+
+ def parseInputWeb(self):
+ '''
+ parse options and provide data provided through the web form
+ '''
+ parsed_options, warnings = self.optionparser.process_form_fields(self.formfields)
+
+ if warnings:
+ raise common.MCFError, '<br/>\n'.join(warnings)
+
+ # no warnings ...
+ self.options.update(parsed_options)
+ self.data_string = self.data
+
+
+ def process(self):
+ '''
+ process input from both web form and CLI
+ '''
+ if not self.webform:
+ self.parseInputCli()
+ else:
+ self.parseInputWeb()
+ # let toolkit parse the molecule, and process it
+ tkmol = self.parseMolecule()
+
+ # we now know how to deal with orphan atoms
+ #atoms, bonds = tkmol.countAtoms(), tkmol.countBonds()
+ #if atoms <= 1 or bonds == 0:
+ #raise common.MCFError, "Input contains no bonds---can't render structure"
+
+ mol = molecule.Molecule(self.options, tkmol)
+
+ return mol
+
+
+ def parseMolecule(self):
+ '''
+ turn the input into a toolkit molecule according to user settings
+
+ indigo is supposed to read transparently, so we can do away with
+ the format setting, basically. If it's numeric, we ask pubchem,
+ if it isn't, we consider it a molecule.
+ '''
+ rawinput = self.data_string
+
+ try:
+ pubchemId = int(rawinput)
+ except ValueError:
+ pubchemId = None
+
+ if pubchemId is not None:
+ try:
+ url = common.pubchem_url % pubchemId
+ pubchemContent = urllib.urlopen(url).read()
+ except IOError:
+ raise common.MCFError, 'No connection to PubChem'
+
+ self.data_string = pubchemContent
+
+ #common.debug('rpc: %s' % self.rpc)
+ #common.debug('data ---\n%s\n---' % self.data_string)
+
+ try:
+ tkmol = Indigo().loadMolecule(self.data_string)
+ except IndigoException:
+ raise common.MCFError, "Invalid input data"
+
+ hydrogens = self.options['hydrogens']
+
+ if hydrogens == 'add':
+ tkmol.unfoldHydrogens()
+ tkmol.layout() # needed to give coordinates to added Hs
+
+ elif hydrogens == 'delete':
+ tkmol.foldHydrogens()
+
+ if not tkmol.hasCoord() or self.options['recalculate_coordinates']:
+ tkmol.layout()
+
+ return tkmol
+
+
+def process(rawargs=None,
+ data=None,
+ formfields=None,
+ progname="mol2chemfig",
+ webform=False,
+ rpc=False):
+ '''
+ process is a convenience wrapper for external callers
+ '''
+ p = Processor(rawargs, data, formfields, progname, webform, rpc)
+
+ try:
+ mol = p.process()
+
+ except HelpError, msg:
+ return False, msg
+
+ except common.MCFError, msg: # anticipated error - brief message enough
+ msg = traceback.format_exc().splitlines()[-1]
+ msg = msg[len('MCFError: '):]
+ return False, msg
+
+ except Exception, msg: # unexpected error - get full traceback
+ tb = traceback.format_exc()
+ return False, tb
+
+ return True, mol \ No newline at end of file
diff --git a/graphics/mol2chemfig/doc/doc-source/mol2chemfig.sty b/graphics/mol2chemfig/latex/mol2chemfig.sty
index 2de1613f91..67af8f52c5 100644
--- a/graphics/mol2chemfig/doc/doc-source/mol2chemfig.sty
+++ b/graphics/mol2chemfig/latex/mol2chemfig.sty
@@ -1,20 +1,15 @@
-% auxiliary package for mol2chemfig
-\ProvidesPackage{mol2chemfig}[2014/03/24 v1.4]
+\ProvidesPackage{mol2chemfig}[2019/11/24 v1.5]
-\RequirePackage{xcolor, chemfig, twoopt, ifmtarg}
+\RequirePackage{xcolor, chemfig, twoopt, ifmtarg, calc, xstring}
\usetikzlibrary{decorations}
-% \setbondstyle is defined by chemfig. Here, we wrap it
-% in order to also save the bond style in a tikz key.
-\let\mcf@setbondstyle\setbondstyle
-\renewcommand{\setbondstyle}[1]{%
- \mcf@setbondstyle{#1}%
- \tikzset{mcfbond/.style={#1}}%
-}
+\def\mcf@three@ea{\expandafter\expandafter\expandafter}
% this macro (by Christian Tellechea) draws circles in aromatic rings.
\def\mcfcringle#1{%
-\tikz\draw[mcfbond](0,0)circle(\CF@atom@sep*#1*0.66667*\CF@cycle@inraduiscoeff);}
+ \mcf@three@ea\tikz\mcf@three@ea\draw\mcf@three@ea[\useKV[chemfig]{chemfig
+ style}](0,0)circle(\useKV[chemfig]{atom
+ sep}*#1*0.66667*\useKV[chemfig]{cycle radius coeff});}
% auxiliary macros for rendering double and triple bonds
@@ -52,10 +47,19 @@
\colorlet{mcfpusharrowcolor}{black}
\colorlet{mcfatomnocolor}{blue}
+\def\CF@@keytomacro#1#2{\edef#1{\unexpanded\expandafter\expandafter\expandafter{\useKV[chemfig]{#2}}}}
+
\tikzset{ % set styles
% wavy bonds. Slightly modified from http://www.texdev.net/tag/chemfig/
+ setatomsep/.code={
+ \CF@@keytomacro\CF@@atomsep{atom sep}
+ \pgfmathsetmacro\mcf@@segmentlength{\CF@@atomsep/6}
+ \pgfmathsetmacro\mcf@@amplitude{\CF@@atomsep/10}
+ },
+ %
mcfwavy/.style =
{
+ setatomsep,
decorate,
decoration =
{
@@ -63,22 +67,20 @@
post length = 0 pt,
pre length = 0 pt,
% Use chemfig's atom spacing
- segment length = \the\dimexpr\csname CF@atom@sep\endcsname/6\relax,
- amplitude = \the\dimexpr\csname CF@atom@sep\endcsname/10\relax
+ segment length=\mcf@@segmentlength,
+ amplitude=\mcf@@amplitude
}
},
% this style is used by the \mcfelmove macro
mcfpusharrow/.style = {
- ->,
+ ->,
mcfpusharrowcolor,
- >=stealth,
+ >=stealth,
shorten <=3pt,
shorten >=2pt,
preaction={draw=mcfbgcolor, -,line width=1.5pt}
},
%
- mcfbond/.style = {}, % the chemfig default bond style is empty, too.
- %
% one bond crossing before another - gets a white backdrop
% as wide as doublesep
mcfbgcolor/.style={white},
@@ -87,11 +89,10 @@
preaction={
draw,
mcfbgcolor,
- line width=\CF@double@sep,
- shorten <= {#1*\CF@double@sep/100},
- shorten >= {#2*\CF@double@sep/100}
- },
- mcfbond
+ line width={\useKV[chemfig]{double bond sep}},
+ shorten <= {#1*\useKV[chemfig]{double bond sep}/100},
+ shorten >= {#2*\useKV[chemfig]{double bond sep}/100}
+ }
},
%
mcfcrossbond/.style={% for backwards compatibility only
@@ -99,37 +100,36 @@
},
%
secondbond/.style 2 args={
- shorten <= {#1*\CF@double@sep/100},
- shorten >= {#2*\CF@double@sep/100},
- mcfbond
+ shorten <= {#1*\useKV[chemfig]{double bond sep}/100},
+ shorten >= {#2*\useKV[chemfig]{double bond sep}/100}
},
%
secondfgbond/.style 2 args={
- preaction={draw,-,mcfbgcolor,line width=\CF@double@sep},
+ preaction={draw,-,mcfbgcolor,line width={\useKV[chemfig]{double bond sep}}},
secondbond={#1}{#2}
},
%
secondleft/.style 2 args={
secondbond={#1}{#2},
- decoration={mcfsecondstroke,raise=\CF@double@sep},
+ decoration={mcfsecondstroke,raise={\useKV[chemfig]{double bond sep}}},
decorate
},
%
secondright/.style 2 args={
secondbond={#1}{#2},
- decoration={mcfsecondstroke,raise=-\CF@double@sep},
+ decoration={mcfsecondstroke,raise=-{\useKV[chemfig]{double bond sep}}},
decorate
},
%
secondfgleft/.style 2 args={
secondfgbond={#1}{#2},
- decoration={mcfsecondstroke,raise=\CF@double@sep},
+ decoration={mcfsecondstroke,raise={\useKV[chemfig]{double bond sep}}},
decorate
},
%
secondfgright/.style 2 args={
secondfgbond={#1}{#2},
- decoration={mcfsecondstroke,raise=-\CF@double@sep},
+ decoration={mcfsecondstroke,raise=-{\useKV[chemfig]{double bond sep}}},
decorate
},
%
@@ -172,7 +172,6 @@
dln/.style={dbl={0}{0}}
}
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Conveniences for drawing push arrows
% the \mcfelmove command is adapted from the
@@ -232,5 +231,3 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% a little help with direct processing of mol2chemfig commands
\newcommand{\mcfinput}[1]{\@@input|"mol2chemfig #1"}
-
-
diff --git a/graphics/mol2chemfig/lua/README b/graphics/mol2chemfig/lua/README
deleted file mode 100644
index 1f3a74e081..0000000000
--- a/graphics/mol2chemfig/lua/README
+++ /dev/null
@@ -1,78 +0,0 @@
-mol2chemfig
------------------------------------------------------------------
-Purpose: Generation of chemfig code from molecular structures
-specified in molfile or smiles format
-
-Licence: LPPL (free)
-
-Author: Michael Palmer (mpalmer@uwaterloo.ca)
-
-Licence: Latex Project Licence (free)
-
-Version: 1.4
------------------------------------------------------------------
-This package contains mol2chemfig.lua, the Lua web client version
-of mol2chemfig. It is used from the command line but calls the
-mol2chemfig server for every request. It expects to be run by
-Lua interpreter that is embedded within the luatex executable.
-
-Requirements:
-
-* LuaTeX (available through TeXLive) or another Lua
- interpreter is required to run the program
-
-* The chemfig LaTeX package is required to compile the
- chemfig code generated by mol2chemfig
--------------------------------------------------------------
-Installation:
-
-1. The preferred installation method is through TeXLive. When
-the script and its prerequisites are installed in this way,
-no additional installation or configuration should be
-necesseary; it should be possible to run "mol2chemfig.lua"
-from a shell window.
-
-Update: The preferred method WOULD be through TeXLive, if
-TeXLive actually had coopted mol2chemfig. This, however,
-does not seem to have happened. So, manual install is
-the only option.
-
-2. If you want to install it manually, you need to ensure that
-both mol2chemfig.lua and your Lua interpreter are in your
-shell's path. Moreover, your Lua interpreter must be able to
-find the auxiliary Lua files (mol2chemfig_client.lua,
-mol2chemfig_dkjson.lua, and mol2chemfig_jsonrpc.lua) also
-included in this package.
-
-LuaTeX's embedded interpreter will use the kpathsea library
-to locate required Lua modules. The directories that it
-will search through are configured in the LUAINPUTS variable
-inside your system's texmf.cnf configuration file.
-
-If you want the script to be run not by luatex but by your
-system's default Lua interpreter, you must change the first
-line in mol2chemfig.lua from
-
-#!/usr/bin/env texlua
-
-to
-
-#!/usr/bin/env lua
-
-and also delete or comment out the line
-
-kpse.set_program_name('luatex')
-
-Moreover, you must ensure that the three other .lua files
-in this package can be located by your lua interpreter.
--------------------------------------------------------------
-Stand-alone version of mol2chemfig
-
-A full locally installable version (as well as the source
-code) of the mol2chemfig program is available at
-
-http://chimpsky.uwaterloo.ca/mol2chemfig
-
-The full program requires Python and the indigo
-cheminformatics library for Python. See the docs
-for additional details. \ No newline at end of file
diff --git a/graphics/mol2chemfig/lua/json.lua b/graphics/mol2chemfig/lua/json.lua
new file mode 100644
index 0000000000..74af4b567a
--- /dev/null
+++ b/graphics/mol2chemfig/lua/json.lua
@@ -0,0 +1,417 @@
+-----------------------------------------------------------------------------
+-- JSON4Lua: JSON encoding / decoding support for the Lua language.
+-- json Module.
+-- Author: Craig Mason-Jones
+-- Homepage: http://github.com/craigmj/json4lua/
+-- Version: 1.0.0
+-- This module is released under the MIT License (MIT).
+-- Please see LICENCE.txt for details.
+--
+-- USAGE:
+-- This module exposes two functions:
+-- json.encode(o)
+-- Returns the table / string / boolean / number / nil / json.null value as a JSON-encoded string.
+-- json.decode(json_string)
+-- Returns a Lua object populated with the data encoded in the JSON string json_string.
+--
+-- REQUIREMENTS:
+-- compat-5.1 if using Lua 5.0
+--
+-- CHANGELOG
+-- 0.9.20 Introduction of local Lua functions for private functions (removed _ function prefix).
+-- Fixed Lua 5.1 compatibility issues.
+-- Introduced json.null to have null values in associative arrays.
+-- json.encode() performance improvement (more than 50%) through table.concat rather than ..
+-- Introduced decode ability to ignore /**/ comments in the JSON string.
+-- 0.9.10 Fix to array encoding / decoding to correctly manage nil/null values in arrays.
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Imports and dependencies
+-----------------------------------------------------------------------------
+local math = require('math')
+local string = require("string")
+local table = require("table")
+
+-----------------------------------------------------------------------------
+-- Module declaration
+-----------------------------------------------------------------------------
+local json = {} -- Public namespace
+local json_private = {} -- Private namespace
+
+-- Public functions
+
+-- Private functions
+local decode_scanArray
+local decode_scanComment
+local decode_scanConstant
+local decode_scanNumber
+local decode_scanObject
+local decode_scanString
+local decode_scanWhitespace
+local encodeString
+local isArray
+local isEncodable
+
+-----------------------------------------------------------------------------
+-- PUBLIC FUNCTIONS
+-----------------------------------------------------------------------------
+--- Encodes an arbitrary Lua object / variable.
+-- @param v The Lua object / variable to be JSON encoded.
+-- @return String containing the JSON encoding in internal Lua string format (i.e. not unicode)
+function json.encode (v)
+ -- Handle nil values
+ if v==nil then
+ return "null"
+ end
+
+ local vtype = type(v)
+
+ -- Handle strings
+ if vtype=='string' then
+ return '"' .. json_private.encodeString(v) .. '"' -- Need to handle encoding in string
+ end
+
+ -- Handle booleans
+ if vtype=='number' or vtype=='boolean' then
+ return tostring(v)
+ end
+
+ -- Handle tables
+ if vtype=='table' then
+ local rval = {}
+ -- Consider arrays separately
+ local bArray, maxCount = isArray(v)
+ if bArray then
+ for i = 1,maxCount do
+ table.insert(rval, json.encode(v[i]))
+ end
+ else -- An object, not an array
+ for i,j in pairs(v) do
+ if isEncodable(i) and isEncodable(j) then
+ table.insert(rval, '"' .. json_private.encodeString(i) .. '":' .. json.encode(j))
+ end
+ end
+ end
+ if bArray then
+ return '[' .. table.concat(rval,',') ..']'
+ else
+ return '{' .. table.concat(rval,',') .. '}'
+ end
+ end
+
+ -- Handle null values
+ if vtype=='function' and v==null then
+ return 'null'
+ end
+
+ assert(false,'encode attempt to encode unsupported type ' .. vtype .. ':' .. tostring(v))
+end
+
+
+--- Decodes a JSON string and returns the decoded value as a Lua data structure / value.
+-- @param s The string to scan.
+-- @param [startPos] Optional starting position where the JSON string is located. Defaults to 1.
+-- @param Lua object, number The object that was scanned, as a Lua table / string / number / boolean or nil,
+-- and the position of the first character after
+-- the scanned JSON object.
+function json.decode(s, startPos)
+ startPos = startPos and startPos or 1
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=string.len(s), 'Unterminated JSON encoded object found at position in [' .. s .. ']')
+ local curChar = string.sub(s,startPos,startPos)
+ -- Object
+ if curChar=='{' then
+ return decode_scanObject(s,startPos)
+ end
+ -- Array
+ if curChar=='[' then
+ return decode_scanArray(s,startPos)
+ end
+ -- Number
+ if string.find("+-0123456789.e", curChar, 1, true) then
+ return decode_scanNumber(s,startPos)
+ end
+ -- String
+ if curChar==[["]] or curChar==[[']] then
+ return decode_scanString(s,startPos)
+ end
+ if string.sub(s,startPos,startPos+1)=='/*' then
+ return decode(s, decode_scanComment(s,startPos))
+ end
+ -- Otherwise, it must be a constant
+ return decode_scanConstant(s,startPos)
+end
+
+--- The null function allows one to specify a null value in an associative array (which is otherwise
+-- discarded if you set the value with 'nil' in Lua. Simply set t = { first=json.null }
+function null()
+ return null -- so json.null() will also return null ;-)
+end
+-----------------------------------------------------------------------------
+-- Internal, PRIVATE functions.
+-- Following a Python-like convention, I have prefixed all these 'PRIVATE'
+-- functions with an underscore.
+-----------------------------------------------------------------------------
+
+--- Scans an array from JSON into a Lua object
+-- startPos begins at the start of the array.
+-- Returns the array and the next starting position
+-- @param s The string being scanned.
+-- @param startPos The starting position for the scan.
+-- @return table, int The scanned array as a table, and the position of the next character to scan.
+function decode_scanArray(s,startPos)
+ local array = {} -- The return value
+ local stringLen = string.len(s)
+ assert(string.sub(s,startPos,startPos)=='[','decode_scanArray called but array does not start at position ' .. startPos .. ' in string:\n'..s )
+ startPos = startPos + 1
+ -- Infinite loop for array elements
+ repeat
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=stringLen,'JSON String ended unexpectedly scanning array.')
+ local curChar = string.sub(s,startPos,startPos)
+ if (curChar==']') then
+ return array, startPos+1
+ end
+ if (curChar==',') then
+ startPos = decode_scanWhitespace(s,startPos+1)
+ end
+ assert(startPos<=stringLen, 'JSON String ended unexpectedly scanning array.')
+ object, startPos = json.decode(s,startPos)
+ table.insert(array,object)
+ until false
+end
+
+--- Scans a comment and discards the comment.
+-- Returns the position of the next character following the comment.
+-- @param string s The JSON string to scan.
+-- @param int startPos The starting position of the comment
+function decode_scanComment(s, startPos)
+ assert( string.sub(s,startPos,startPos+1)=='/*', "decode_scanComment called but comment does not start at position " .. startPos)
+ local endPos = string.find(s,'*/',startPos+2)
+ assert(endPos~=nil, "Unterminated comment in string at " .. startPos)
+ return endPos+2
+end
+
+--- Scans for given constants: true, false or null
+-- Returns the appropriate Lua type, and the position of the next character to read.
+-- @param s The string being scanned.
+-- @param startPos The position in the string at which to start scanning.
+-- @return object, int The object (true, false or nil) and the position at which the next character should be
+-- scanned.
+function decode_scanConstant(s, startPos)
+ local consts = { ["true"] = true, ["false"] = false, ["null"] = nil }
+ local constNames = {"true","false","null"}
+
+ for i,k in pairs(constNames) do
+ if string.sub(s,startPos, startPos + string.len(k) -1 )==k then
+ return consts[k], startPos + string.len(k)
+ end
+ end
+ assert(nil, 'Failed to scan constant from string ' .. s .. ' at starting position ' .. startPos)
+end
+
+--- Scans a number from the JSON encoded string.
+-- (in fact, also is able to scan numeric +- eqns, which is not
+-- in the JSON spec.)
+-- Returns the number, and the position of the next character
+-- after the number.
+-- @param s The string being scanned.
+-- @param startPos The position at which to start scanning.
+-- @return number, int The extracted number and the position of the next character to scan.
+function decode_scanNumber(s,startPos)
+ local endPos = startPos+1
+ local stringLen = string.len(s)
+ local acceptableChars = "+-0123456789.e"
+ while (string.find(acceptableChars, string.sub(s,endPos,endPos), 1, true)
+ and endPos<=stringLen
+ ) do
+ endPos = endPos + 1
+ end
+ local stringValue = 'return ' .. string.sub(s,startPos, endPos-1)
+ local stringEval = load(stringValue)
+ assert(stringEval, 'Failed to scan number [ ' .. stringValue .. '] in JSON string at position ' .. startPos .. ' : ' .. endPos)
+ return stringEval(), endPos
+end
+
+--- Scans a JSON object into a Lua object.
+-- startPos begins at the start of the object.
+-- Returns the object and the next starting position.
+-- @param s The string being scanned.
+-- @param startPos The starting position of the scan.
+-- @return table, int The scanned object as a table and the position of the next character to scan.
+function decode_scanObject(s,startPos)
+ local object = {}
+ local stringLen = string.len(s)
+ local key, value
+ assert(string.sub(s,startPos,startPos)=='{','decode_scanObject called but object does not start at position ' .. startPos .. ' in string:\n' .. s)
+ startPos = startPos + 1
+ repeat
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly while scanning object.')
+ local curChar = string.sub(s,startPos,startPos)
+ if (curChar=='}') then
+ return object,startPos+1
+ end
+ if (curChar==',') then
+ startPos = decode_scanWhitespace(s,startPos+1)
+ end
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly scanning object.')
+ -- Scan the key
+ key, startPos = json.decode(s,startPos)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
+ assert(string.sub(s,startPos,startPos)==':','JSON object key-value assignment mal-formed at ' .. startPos)
+ startPos = decode_scanWhitespace(s,startPos+1)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
+ value, startPos = json.decode(s,startPos)
+ object[key]=value
+ until false -- infinite loop while key-value pairs are found
+end
+
+-- START SoniEx2
+-- Initialize some things used by decode_scanString
+-- You know, for efficiency
+local escapeSequences = {
+ ["\\t"] = "\t",
+ ["\\f"] = "\f",
+ ["\\r"] = "\r",
+ ["\\n"] = "\n",
+ ["\\b"] = "\b"
+}
+setmetatable(escapeSequences, {__index = function(t,k)
+ -- skip "\" aka strip escape
+ return string.sub(k,2)
+end})
+-- END SoniEx2
+
+--- Scans a JSON string from the opening inverted comma or single quote to the
+-- end of the string.
+-- Returns the string extracted as a Lua string,
+-- and the position of the next non-string character
+-- (after the closing inverted comma or single quote).
+-- @param s The string being scanned.
+-- @param startPos The starting position of the scan.
+-- @return string, int The extracted string as a Lua string, and the next character to parse.
+function decode_scanString(s,startPos)
+ assert(startPos, 'decode_scanString(..) called without start position')
+ local startChar = string.sub(s,startPos,startPos)
+ -- START SoniEx2
+ -- PS: I don't think single quotes are valid JSON
+ assert(startChar == [["]] or startChar == [[']],'decode_scanString called for a non-string')
+ --assert(startPos, "String decoding failed: missing closing " .. startChar .. " for string at position " .. oldStart)
+ local t = {}
+ local i,j = startPos,startPos
+ while string.find(s, startChar, j+1) ~= j+1 do
+ local oldj = j
+ i,j = string.find(s, "\\.", j+1)
+ local x,y = string.find(s, startChar, oldj+1)
+ if not i or x < i then
+ i,j = x,y-1
+ end
+ table.insert(t, string.sub(s, oldj+1, i-1))
+ if string.sub(s, i, j) == "\\u" then
+ local a = string.sub(s,j+1,j+4)
+ j = j + 4
+ local n = tonumber(a, 16)
+ assert(n, "String decoding failed: bad Unicode escape " .. a .. " at position " .. i .. " : " .. j)
+ -- math.floor(x/2^y) == lazy right shift
+ -- a % 2^b == bitwise_and(a, (2^b)-1)
+ -- 64 = 2^6
+ -- 4096 = 2^12 (or 2^6 * 2^6)
+ local x
+ if n < 0x80 then
+ x = string.char(n % 0x80)
+ elseif n < 0x800 then
+ -- [110x xxxx] [10xx xxxx]
+ x = string.char(0xC0 + (math.floor(n/64) % 0x20), 0x80 + (n % 0x40))
+ else
+ -- [1110 xxxx] [10xx xxxx] [10xx xxxx]
+ x = string.char(0xE0 + (math.floor(n/4096) % 0x10), 0x80 + (math.floor(n/64) % 0x40), 0x80 + (n % 0x40))
+ end
+ table.insert(t, x)
+ else
+ table.insert(t, escapeSequences[string.sub(s, i, j)])
+ end
+ end
+ table.insert(t,string.sub(j, j+1))
+ assert(string.find(s, startChar, j+1), "String decoding failed: missing closing " .. startChar .. " at position " .. j .. "(for string at position " .. startPos .. ")")
+ return table.concat(t,""), j+2
+ -- END SoniEx2
+end
+
+--- Scans a JSON string skipping all whitespace from the current start position.
+-- Returns the position of the first non-whitespace character, or nil if the whole end of string is reached.
+-- @param s The string being scanned
+-- @param startPos The starting position where we should begin removing whitespace.
+-- @return int The first position where non-whitespace was encountered, or string.len(s)+1 if the end of string
+-- was reached.
+function decode_scanWhitespace(s,startPos)
+ local whitespace=" \n\r\t"
+ local stringLen = string.len(s)
+ while ( string.find(whitespace, string.sub(s,startPos,startPos), 1, true) and startPos <= stringLen) do
+ startPos = startPos + 1
+ end
+ return startPos
+end
+
+--- Encodes a string to be JSON-compatible.
+-- This just involves back-quoting inverted commas, back-quotes and newlines, I think ;-)
+-- @param s The string to return as a JSON encoded (i.e. backquoted string)
+-- @return The string appropriately escaped.
+
+local escapeList = {
+ ['"'] = '\\"',
+ ['\\'] = '\\\\',
+ ['/'] = '\\/',
+ ['\b'] = '\\b',
+ ['\f'] = '\\f',
+ ['\n'] = '\\n',
+ ['\r'] = '\\r',
+ ['\t'] = '\\t'
+}
+
+function json_private.encodeString(s)
+ local s = tostring(s)
+ return s:gsub(".", function(c) return escapeList[c] end) -- SoniEx2: 5.0 compat
+end
+
+-- Determines whether the given Lua type is an array or a table / dictionary.
+-- We consider any table an array if it has indexes 1..n for its n items, and no
+-- other data in the table.
+-- I think this method is currently a little 'flaky', but can't think of a good way around it yet...
+-- @param t The table to evaluate as an array
+-- @return boolean, number True if the table can be represented as an array, false otherwise. If true,
+-- the second returned value is the maximum
+-- number of indexed elements in the array.
+function isArray(t)
+ -- Next we count all the elements, ensuring that any non-indexed elements are not-encodable
+ -- (with the possible exception of 'n')
+ local maxIndex = 0
+ for k,v in pairs(t) do
+ if (type(k)=='number' and math.floor(k)==k and 1<=k) then -- k,v is an indexed pair
+ if (not isEncodable(v)) then return false end -- All array elements must be encodable
+ maxIndex = math.max(maxIndex,k)
+ else
+ if (k=='n') then
+ if v ~= table.getn(t) then return false end -- False if n does not hold the number of elements
+ else -- Else of (k=='n')
+ if isEncodable(v) then return false end
+ end -- End of (k~='n')
+ end -- End of k,v not an indexed pair
+ end -- End of loop across all pairs
+ return true, maxIndex
+end
+
+--- Determines whether the given Lua object / table / variable can be JSON encoded. The only
+-- types that are JSON encodable are: string, boolean, number, nil, table and json.null.
+-- In this implementation, all other types are ignored.
+-- @param o The object to examine.
+-- @return boolean True if the object should be JSON encoded, false if it should be ignored.
+function isEncodable(o)
+ local t = type(o)
+ return (t=='string' or t=='boolean' or t=='number' or t=='nil' or t=='table') or (t=='function' and o==null)
+end
+
+return json
diff --git a/graphics/mol2chemfig/lua/mol2chemfig.lua b/graphics/mol2chemfig/lua/mol2chemfig.lua
index c6bf991651..0800613e8b 100755
--- a/graphics/mol2chemfig/lua/mol2chemfig.lua
+++ b/graphics/mol2chemfig/lua/mol2chemfig.lua
@@ -6,18 +6,12 @@
Purpose: Generation of chemfig code from molecular structures specified
in molfile or smiles format
- Licence: LPPL (free)
+ Licence: LaTeX public licence
-------------------------------------------------------------------------
This script acts as a thin client; it passes off all work to a server
installation of the mol2chemfig program. Therefore, you need to be
online for this program to work.
- The server is accessed using the IP address instead of the URL, which
- saves a DNS lookup. However, if things don't work, the IP might have
- changed. In that case, you might try this URL:
-
- server_address = "http://chimpsky.uwaterloo.ca/mol2chemfig/luabackend"
-
The "kpse.set_program_name('luatex')" call causes the use of kpathsea to
locate imported modules. The mol2chemfig-client.lua module should then be
found if installed along the LUAINPUTS path that is set in your texmf.cnf
@@ -26,8 +20,8 @@
send bug reports and lots of money to mpalmer@uwaterloo.ca
]]--
-server_address = "http://129.97.80.65/mol2chemfig/luabackend"
+server_address = "http://chimpsky.uwaterloo.ca/mol2chemfig/luabackend"
kpse.set_program_name('luatex')
-require('mol2chemfig_client.lua')
+require('mol2chemfig_client_1_2.lua')
diff --git a/graphics/mol2chemfig/lua/mol2chemfig_client.lua b/graphics/mol2chemfig/lua/mol2chemfig_client_1_2.lua
index da0756f6a1..fabf68cce9 100644
--- a/graphics/mol2chemfig/lua/mol2chemfig_client.lua
+++ b/graphics/mol2chemfig/lua/mol2chemfig_client_1_2.lua
@@ -1,15 +1,15 @@
-- Command-line-driven web client for mol2chemfig.
-local client_version = "1.1"
-
-local jsonrpc = require("mol2chemfig_jsonrpc")
local os = require("os")
local io = require("io")
-local server = jsonrpc.proxy(server_address) -- server_address must be in scope
+local json = require("json")
+require("rpc") -- modifies json in place to add rpc namespace
local progname = arg[0]
+local client_version = "1.2"
-local server_info, error = server.info(progname, client_version)
+server = json.rpc.proxy(server_address)
+local server_info, error = server.info({progname, client_version})
if error then
io.stderr:write("Error: ", error)
@@ -108,10 +108,10 @@ else
end
-- process options and data
-local result, error = server.process(progname, user_options, data)
+local result, error = server.process({progname, user_options, data})
if error then
io.stderr:write(error .. '\n')
else
print(result)
-end \ No newline at end of file
+end
diff --git a/graphics/mol2chemfig/lua/mol2chemfig_dkjson.lua b/graphics/mol2chemfig/lua/mol2chemfig_dkjson.lua
deleted file mode 100644
index 6a53a48e95..0000000000
--- a/graphics/mol2chemfig/lua/mol2chemfig_dkjson.lua
+++ /dev/null
@@ -1,646 +0,0 @@
- --[==[
-
-modified by M. Palmer from:
-
-David Kolf's JSON module for Lua 5.1/5.2 (Version 2.1)
-
-In this abridged version, the lpeg library is never used, and the
-corresponding settings and functions have been removed. The remainder
-of the code remains unchanged.
-
-------
-
-This module writes no global values, not even the module table.
-Import it using
-
- json = require ("dkjsonmod")
-
-Exported functions and values:
-
-`json.encode (object [, state])`
---------------------------------
-
-Create a string representing the object. `Object` can be a table,
-a string, a number, a boolean, `nil`, `json.null` or any object with
-a function `__tojson` in its metatable. A table can only use strings
-and numbers as keys and its values have to be valid objects as
-well. It raises an error for any invalid data types or reference
-cycles.
-
-`state` is an optional table with the following fields:
-
- - `indent`
- When `indent` (a boolean) is set, the created string will contain
- newlines and indentations. Otherwise it will be one long line.
- - `keyorder`
- `keyorder` is an array to specify the ordering of keys in the
- encoded output. If an object has keys which are not in this array
- they are written after the sorted keys.
- - `level`
- This is the initial level of indentation used when `indent` is
- set. For each level two spaces are added. When absent it is set
- to 0.
- - `buffer`
- `buffer` is an array to store the strings for the result so they
- can be concatenated at once. When it isn't given, the encode
- function will create it temporary and will return the
- concatenated result.
- - `bufferlen`
- When `bufferlen` is set, it has to be the index of the last
- element of `buffer`.
- - `tables`
- `tables` is a set to detect reference cycles. It is created
- temporary when absent. Every table that is currently processed
- is used as key, the value is `true`.
-
-When `state.buffer` was set, the return value will be `true` on
-success. Without `state.buffer` the return value will be a string.
-
-`json.decode (string [, position [, null]])`
---------------------------------------------
-
-Decode `string` starting at `position` or at 1 if `position` was
-omitted.
-
-`null` is an optional value to be returned for null values. The
-default is `nil`, but you could set it to `json.null` or any other
-value.
-
-The return values are the object or `nil`, the position of the next
-character that doesn't belong to the object, and in case of errors
-an error message.
-
-Two metatables are created. Every array or object that is decoded gets
-a metatable with the `__jsontype` field set to either `array` or
-`object`. If you want to provide your own metatables use the syntax
-
- json.decode (string, position, null, objectmeta, arraymeta)
-
-`<metatable>.__jsonorder`
--------------------------
-
-`__jsonorder` can overwrite the `keyorder` for a specific table.
-
-`<metatable>.__jsontype`
-------------------------
-
-`__jsontype` can be either `"array"` or `"object"`. This is mainly useful
-for tables that can be empty. (The default for empty tables is
-`"array"`).
-
-`<metatable>.__tojson (self, state)`
-------------------------------------
-
-You can provide your own `__tojson` function in a metatable. In this
-function you can either add directly to the buffer and return true,
-or you can return a string. On errors nil and a message should be
-returned.
-
-`json.null`
------------
-
-You can use this value for setting explicit `null` values.
-
-`json.version`
---------------
-
-Set to `"dkjson 2.1"`.
-
-`json.quotestring (string)`
----------------------------
-
-Quote a UTF-8 string and escape critical characters using JSON
-escape sequences. This function is only necessary when you build
-your own `__tojson` functions.
-
-`json.addnewline (state)`
--------------------------
-
-When `state.indent` is set, add a newline to `state.buffer` and spaces
-according to `state.level`.
-
-LPeg support
-------------
-
-(removed)
-
-You can contact the author by sending an e-mail to 'kolf' at the
-e-mail provider 'gmx.de'.
-
----------------------------------------------------------------------
-
-*Copyright (C) 2010, 2011 David Heiko Kolf*
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
---]==]
-
--- global dependencies:
-local pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset =
- pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset
-local error, require, pcall = error, require, pcall
-local floor, huge = math.floor, math.huge
-local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat =
- string.rep, string.gsub, string.sub, string.byte, string.char,
- string.find, string.len, string.format
-local concat = table.concat
-
-if _VERSION == 'Lua 5.1' then
- local function noglobals (s,k,v) error ("global access: " .. k, 2) end
- setfenv (1, setmetatable ({}, { __index = noglobals, __newindex = noglobals }))
-end
-local _ENV = nil -- blocking globals in Lua 5.2
-
-local json = { version = "dkjson 2.1" }
-
-pcall (function()
- -- Enable access to blocked metatables.
- -- Don't worry, this module doesn't change anything in them.
- local debmeta = require "debug".getmetatable
- if debmeta then getmetatable = debmeta end
-end)
-
-json.null = setmetatable ({}, {
- __tojson = function () return "null" end
-})
-
-local function isarray (tbl)
- local max, n, arraylen = 0, 0, 0
- for k,v in pairs (tbl) do
- if k == 'n' and type(v) == 'number' then
- arraylen = v
- if v > max then
- max = v
- end
- else
- if type(k) ~= 'number' or k < 1 or floor(k) ~= k then
- return false
- end
- if k > max then
- max = k
- end
- n = n + 1
- end
- end
- if max > 10 and max > arraylen and max > n * 2 then
- return false -- don't create an array with too many holes
- end
- return true, max
-end
-
-local escapecodes = {
- ["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
- ["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"
-}
-
-local function escapeutf8 (uchar)
- local value = escapecodes[uchar]
- if value then
- return value
- end
- local a, b, c, d = strbyte (uchar, 1, 4)
- a, b, c, d = a or 0, b or 0, c or 0, d or 0
- if a <= 0x7f then
- value = a
- elseif 0xc0 <= a and a <= 0xdf and b >= 0x80 then
- value = (a - 0xc0) * 0x40 + b - 0x80
- elseif 0xe0 <= a and a <= 0xef and b >= 0x80 and c >= 0x80 then
- value = ((a - 0xe0) * 0x40 + b - 0x80) * 0x40 + c - 0x80
- elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
- value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
- else
- return ""
- end
- if value <= 0xffff then
- return strformat ("\\u%.4x", value)
- elseif value <= 0x10ffff then
- -- encode as UTF-16 surrogate pair
- value = value - 0x10000
- local highsur, lowsur = 0xD800 + floor (value/0x400), 0xDC00 + (value % 0x400)
- return strformat ("\\u%.4x\\u%.4x", highsur, lowsur)
- else
- return ""
- end
-end
-
-local function fsub (str, pattern, repl)
- -- gsub always builds a new string in a buffer, even when no match
- -- exists. First using find should be more efficient when most strings
- -- don't contain the pattern.
- if strfind (str, pattern) then
- return gsub (str, pattern, repl)
- else
- return str
- end
-end
-
-local function quotestring (value)
- -- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
- value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8)
- if strfind (value, "[\194\216\220\225\226\239]") then
- value = fsub (value, "\194[\128-\159\173]", escapeutf8)
- value = fsub (value, "\216[\128-\132]", escapeutf8)
- value = fsub (value, "\220\143", escapeutf8)
- value = fsub (value, "\225\158[\180\181]", escapeutf8)
- value = fsub (value, "\226\128[\140-\143\168\175]", escapeutf8)
- value = fsub (value, "\226\129[\160-\175]", escapeutf8)
- value = fsub (value, "\239\187\191", escapeutf8)
- value = fsub (value, "\239\191[\176\191]", escapeutf8)
- end
- return "\"" .. value .. "\""
-end
-json.quotestring = quotestring
-
-local function addnewline2 (level, buffer, buflen)
- buffer[buflen+1] = "\n"
- buffer[buflen+2] = strrep (" ", level)
- buflen = buflen + 2
- return buflen
-end
-
-function json.addnewline (state)
- if state.indent then
- state.bufferlen = addnewline2 (state.level or 0,
- state.buffer, state.bufferlen or #(state.buffer))
- end
-end
-
-local encode2 -- forward declaration
-
-local function addpair (key, value, prev, indent, level, buffer, buflen, tables, globalorder)
- local kt = type (key)
- if kt ~= 'string' and kt ~= 'number' then
- return nil, "type '" .. kt .. "' is not supported as a key by JSON."
- end
- if prev then
- buflen = buflen + 1
- buffer[buflen] = ","
- end
- if indent then
- buflen = addnewline2 (level, buffer, buflen)
- end
- buffer[buflen+1] = quotestring (key)
- buffer[buflen+2] = ":"
- return encode2 (value, indent, level, buffer, buflen + 2, tables, globalorder)
-end
-
-encode2 = function (value, indent, level, buffer, buflen, tables, globalorder)
- local valtype = type (value)
- local valmeta = getmetatable (value)
- valmeta = type (valmeta) == 'table' and valmeta -- only tables
- local valtojson = valmeta and valmeta.__tojson
- if valtojson then
- if tables[value] then
- return nil, "reference cycle"
- end
- tables[value] = true
- local state = {
- indent = indent, level = level, buffer = buffer,
- bufferlen = buflen, tables = tables, keyorder = globalorder
- }
- local ret, msg = valtojson (value, state)
- if not ret then return nil, msg end
- tables[value] = nil
- buflen = state.bufferlen
- if type (ret) == 'string' then
- buflen = buflen + 1
- buffer[buflen] = ret
- end
- elseif value == nil then
- buflen = buflen + 1
- buffer[buflen] = "null"
- elseif valtype == 'number' then
- local s
- if value ~= value or value >= huge or -value >= huge then
- -- This is the behaviour of the original JSON implementation.
- s = "null"
- else
- s = tostring (value)
- end
- buflen = buflen + 1
- buffer[buflen] = s
- elseif valtype == 'boolean' then
- buflen = buflen + 1
- buffer[buflen] = value and "true" or "false"
- elseif valtype == 'string' then
- buflen = buflen + 1
- buffer[buflen] = quotestring (value)
- elseif valtype == 'table' then
- if tables[value] then
- return nil, "reference cycle"
- end
- tables[value] = true
- level = level + 1
- local metatype = valmeta and valmeta.__jsontype
- local isa, n
- if metatype == 'array' then
- isa = true
- n = value.n or #value
- elseif metatype == 'object' then
- isa = false
- else
- isa, n = isarray (value)
- end
- local msg
- if isa then -- JSON array
- buflen = buflen + 1
- buffer[buflen] = "["
- for i = 1, n do
- buflen, msg = encode2 (value[i], indent, level, buffer, buflen, tables, globalorder)
- if not buflen then return nil, msg end
- if i < n then
- buflen = buflen + 1
- buffer[buflen] = ","
- end
- end
- buflen = buflen + 1
- buffer[buflen] = "]"
- else -- JSON object
- local prev = false
- buflen = buflen + 1
- buffer[buflen] = "{"
- local order = valmeta and valmeta.__jsonorder or globalorder
- if order then
- local used = {}
- n = #order
- for i = 1, n do
- local k = order[i]
- local v = value[k]
- if v then
- used[k] = true
- buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder)
- prev = true -- add a seperator before the next element
- end
- end
- for k,v in pairs (value) do
- if not used[k] then
- buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder)
- if not buflen then return nil, msg end
- prev = true -- add a seperator before the next element
- end
- end
- else -- unordered
- for k,v in pairs (value) do
- buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder)
- if not buflen then return nil, msg end
- prev = true -- add a seperator before the next element
- end
- end
- if indent then
- buflen = addnewline2 (level - 1, buffer, buflen)
- end
- buflen = buflen + 1
- buffer[buflen] = "}"
- end
- tables[value] = nil
- else
- return nil, "type '" .. valtype .. "' is not supported by JSON."
- end
- return buflen
-end
-
-function json.encode (value, state)
- state = state or {}
- local oldbuffer = state.buffer
- local buffer = oldbuffer or {}
- local ret, msg = encode2 (value, state.indent, state.level or 0,
- buffer, state.bufferlen or 0, state.tables or {}, state.keyorder)
- if not ret then
- error (msg, 2)
- elseif oldbuffer then
- state.bufferlen = ret
- return true
- else
- return concat (buffer)
- end
-end
-
-local function loc (str, where)
- local line, pos, linepos = 1, 1, 1
- while true do
- pos = strfind (str, "\n", pos, true)
- if pos and pos < where then
- line = line + 1
- linepos = pos
- pos = pos + 1
- else
- break
- end
- end
- return "line " .. line .. ", column " .. (where - linepos)
-end
-
-local function unterminated (str, what, where)
- return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where)
-end
-
-local function scanwhite (str, pos)
- while true do
- pos = strfind (str, "%S", pos)
- if not pos then return nil end
- if strsub (str, pos, pos + 2) == "\239\187\191" then
- -- UTF-8 Byte Order Mark
- pos = pos + 3
- else
- return pos
- end
- end
-end
-
-local escapechars = {
- ["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f",
- ["n"] = "\n", ["r"] = "\r", ["t"] = "\t"
-}
-
-local function unichar (value)
- if value < 0 then
- return nil
- elseif value <= 0x007f then
- return strchar (value)
- elseif value <= 0x07ff then
- return strchar (0xc0 + floor(value/0x40),
- 0x80 + (floor(value) % 0x40))
- elseif value <= 0xffff then
- return strchar (0xe0 + floor(value/0x1000),
- 0x80 + (floor(value/0x40) % 0x40),
- 0x80 + (floor(value) % 0x40))
- elseif value <= 0x10ffff then
- return strchar (0xf0 + floor(value/0x40000),
- 0x80 + (floor(value/0x1000) % 0x40),
- 0x80 + (floor(value/0x40) % 0x40),
- 0x80 + (floor(value) % 0x40))
- else
- return nil
- end
-end
-
-local function scanstring (str, pos)
- local lastpos = pos + 1
- local buffer, n = {}, 0
- while true do
- local nextpos = strfind (str, "[\"\\]", lastpos)
- if not nextpos then
- return unterminated (str, "string", pos)
- end
- if nextpos > lastpos then
- n = n + 1
- buffer[n] = strsub (str, lastpos, nextpos - 1)
- end
- if strsub (str, nextpos, nextpos) == "\"" then
- lastpos = nextpos + 1
- break
- else
- local escchar = strsub (str, nextpos + 1, nextpos + 1)
- local value
- if escchar == "u" then
- value = tonumber (strsub (str, nextpos + 2, nextpos + 5), 16)
- if value then
- local value2
- if 0xD800 <= value and value <= 0xDBff then
- -- we have the high surrogate of UTF-16. Check if there is a
- -- low surrogate escaped nearby to combine them.
- if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then
- value2 = tonumber (strsub (str, nextpos + 8, nextpos + 11), 16)
- if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then
- value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000
- else
- value2 = nil -- in case it was out of range for a low surrogate
- end
- end
- end
- value = value and unichar (value)
- if value then
- if value2 then
- lastpos = nextpos + 12
- else
- lastpos = nextpos + 6
- end
- end
- end
- end
- if not value then
- value = escapechars[escchar] or escchar
- lastpos = nextpos + 2
- end
- n = n + 1
- buffer[n] = value
- end
- end
- if n == 1 then
- return buffer[1], lastpos
- elseif n > 1 then
- return concat (buffer), lastpos
- else
- return "", lastpos
- end
-end
-
-local scanvalue -- forward declaration
-
-local function scantable (what, closechar, str, startpos, nullval, objectmeta, arraymeta)
- local len = strlen (str)
- local tbl, n = {}, 0
- local pos = startpos + 1
- if what == 'object' then
- setmetatable (tbl, objectmeta)
- else
- setmetatable (tbl, arraymeta)
- end
- while true do
- pos = scanwhite (str, pos)
- if not pos then return unterminated (str, what, startpos) end
- local char = strsub (str, pos, pos)
- if char == closechar then
- return tbl, pos + 1
- end
- local val1, err
- val1, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
- if err then return nil, pos, err end
- pos = scanwhite (str, pos)
- if not pos then return unterminated (str, what, startpos) end
- char = strsub (str, pos, pos)
- if char == ":" then
- if val1 == nil then
- return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")"
- end
- pos = scanwhite (str, pos + 1)
- if not pos then return unterminated (str, what, startpos) end
- local val2
- val2, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
- if err then return nil, pos, err end
- tbl[val1] = val2
- pos = scanwhite (str, pos)
- if not pos then return unterminated (str, what, startpos) end
- char = strsub (str, pos, pos)
- else
- n = n + 1
- tbl[n] = val1
- end
- if char == "," then
- pos = pos + 1
- end
- end
-end
-
-scanvalue = function (str, pos, nullval, objectmeta, arraymeta)
- pos = pos or 1
- pos = scanwhite (str, pos)
- if not pos then
- return nil, strlen (str) + 1, "no valid JSON value (reached the end)"
- end
- local char = strsub (str, pos, pos)
- if char == "{" then
- return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta)
- elseif char == "[" then
- return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta)
- elseif char == "\"" then
- return scanstring (str, pos)
- else
- local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos)
- if pstart then
- local number = tonumber (strsub (str, pstart, pend))
- if number then
- return number, pend + 1
- end
- end
- pstart, pend = strfind (str, "^%a%w*", pos)
- if pstart then
- local name = strsub (str, pstart, pend)
- if name == "true" then
- return true, pend + 1
- elseif name == "false" then
- return false, pend + 1
- elseif name == "null" then
- return nullval, pend + 1
- end
- end
- return nil, pos, "no valid JSON value at " .. loc (str, pos)
- end
-end
-
-function json.decode (str, pos, nullval, objectmeta, arraymeta)
- objectmeta = objectmeta or {__jsontype = 'object'}
- arraymeta = arraymeta or {__jsontype = 'array'}
- return scanvalue (str, pos, nullval, objectmeta, arraymeta)
-end
-
-
-return json
diff --git a/graphics/mol2chemfig/lua/mol2chemfig_jsonrpc.lua b/graphics/mol2chemfig/lua/mol2chemfig_jsonrpc.lua
deleted file mode 100644
index 66c8ce7211..0000000000
--- a/graphics/mol2chemfig/lua/mol2chemfig_jsonrpc.lua
+++ /dev/null
@@ -1,86 +0,0 @@
------------------------------------------------------------------------------
--- modified by Michael Palmer from:
-
--- JSONRPC4Lua: JSON RPC client calls over http for the Lua language.
--- json.rpc Module.
--- Author: Craig Mason-Jones
--- Homepage: http://json.luaforge.net/
--- Version: 0.9.40
--- This module is released under the MIT License (MIT).
---
--- REQUIREMENTS:
--- Lua socket 2.0 (http://www.cs.princeton.edu/~diego/professional/luasocket/)
--- mol2chemfig_dkjson.lua
--- compat-5.1 if using Lua 5.0.
------------------------------------------------------------------------------
-
------------------------------------------------------------------------------
--- Imports and dependencies
------------------------------------------------------------------------------
-local json = require("mol2chemfig_dkjson")
-local http = require("socket.http")
-local assert = assert
-local require = require
-local string = string
-local table = table
-local setmetatable = setmetatable
-local unpack = unpack
-
-local base = _G
-
-module("mol2chemfig_jsonrpc")
-
-
------------------------------------------------------------------------------
--- PUBLIC functions
------------------------------------------------------------------------------
-
-function proxy(url)
- local serverProxy = {}
- local proxyMeta = {
- __index = function(t, key)
- return function(...)
- return call(url, key, unpack(arg))
- end
- end
- }
- setmetatable(serverProxy, proxyMeta)
- return serverProxy
-end
-
-
-function call(url, method, ...)
- assert(method,'method param is nil to call')
- local JSONRequestArray = {
- id = "httpRequest",
- method = method,
- params = arg
- }
- local httpResponse, result, code
- local jsonRequest = json.encode(JSONRequestArray)
- local ltn12 = require('ltn12')
- local resultChunks = {}
- httpResponse, code = http.request(
- { url = url,
- sink = ltn12.sink.table(resultChunks),
- method = 'POST',
- headers = {
- ['content-type']='text/plain',
- ['content-length']=string.len(jsonRequest)
- },
- source = ltn12.source.string(jsonRequest)
- }
- )
- httpResponse = table.concat(resultChunks)
- -- Check the http response code
- if (code~=200) then
- return nil, "HTTP ERROR: " .. code
- end
- -- And decode the httpResponse and check the JSON RPC result code
- result = json.decode( httpResponse )
- if result.result then
- return result.result, nil
- else
- return nil, result.error
- end
-end
diff --git a/graphics/mol2chemfig/lua/rpc.lua b/graphics/mol2chemfig/lua/rpc.lua
new file mode 100644
index 0000000000..d162ee575e
--- /dev/null
+++ b/graphics/mol2chemfig/lua/rpc.lua
@@ -0,0 +1,105 @@
+-----------------------------------------------------------------------------
+-- JSONRPC4Lua: JSON RPC client calls over http for the Lua language.
+-- json.rpc Module.
+-- Author: Craig Mason-Jones
+-- Homepage: http://github.com/craigmj/json4lua/
+-- Version: 1.0.0
+-- This module is released under the MIT License (MIT).
+-- Please see LICENCE.txt for details.
+--
+-- USAGE:
+-- This module exposes two functions:
+-- proxy( 'url')
+-- Returns a proxy object for calling the JSON RPC Service at the given url.
+-- call ( 'url', 'method', ...)
+-- Calls the JSON RPC server at the given url, invokes the appropriate method, and
+-- passes the remaining parameters. Returns the result and the error. If the result is nil, an error
+-- should be there (or the system returned a null). If an error is there, the result should be nil.
+--
+-- REQUIREMENTS:
+-- Lua socket 2.0 (http://www.cs.princeton.edu/~diego/professional/luasocket/)
+-- json (The JSON4Lua package with which it is bundled)
+-- compat-5.1 if using Lua 5.0.
+-----------------------------------------------------------------------------
+
+local json = require('json')
+json.rpc = {} -- Module public namespace
+
+-----------------------------------------------------------------------------
+-- Imports and dependencies
+-----------------------------------------------------------------------------
+local http = require("socket.http")
+
+-----------------------------------------------------------------------------
+-- PUBLIC functions
+-----------------------------------------------------------------------------
+
+--- Creates an RPC Proxy object for the given Url of a JSON-RPC server.
+-- @param url The URL for the JSON RPC Server.
+-- @return Object on which JSON-RPC remote methods can be called.
+-- EXAMPLE Usage:
+-- local jsolait = json.rpc.proxy('http://jsolait.net/testj.py')
+-- print(jsolait.echo('This is a test of the echo method!'))
+-- print(jsolait.args2String('first','second','third'))
+-- table.foreachi( jsolait.args2Array(5,4,3,2,1), print)
+function json.rpc.proxy(url)
+ local serverProxy = {}
+ local proxyMeta = {
+ __index = function(self, key)
+ return function(...)
+ return json.rpc.call(url, key, ...)
+ end
+ end
+ }
+ setmetatable(serverProxy, proxyMeta)
+ return serverProxy
+end
+
+--- Calls a JSON RPC method on a remote server.
+-- Returns a boolean true if the call succeeded, false otherwise.
+-- On success, the second returned parameter is the decoded
+-- JSON object from the server.
+-- On http failure, returns nil and an error message.
+-- On success, returns the result and nil.
+-- @param url The url of the JSON RPC server.
+-- @param method The method being called.
+-- @param ... Parameters to pass to the method.
+-- @return result, error The JSON RPC result and error. One or the other should be nil. If both
+-- are nil, this means that the result of the RPC call was nil.
+-- EXAMPLE Usage:
+-- print(json.rpc.call('http://jsolait.net/testj.py','echo','This string will be returned'))
+function json.rpc.call(url, method, ...)
+ local JSONRequestArray = {
+ id=tostring(math.random()),
+ ["method"]=method,
+ params = ...
+ }
+ local httpResponse, result, code
+ local jsonRequest = json.encode(JSONRequestArray)
+ -- We use the sophisticated http.request form (with ltn12 sources and sinks) so that
+ -- we can set the content-type to text/plain. While this shouldn't strictly-speaking be true,
+ -- it seems a good idea (Xavante won't work w/out a content-type header, although a patch
+ -- is needed to Xavante to make it work with text/plain)
+ local ltn12 = require('ltn12')
+ local resultChunks = {}
+ httpResponse, code = http.request(
+ { ['url'] = url,
+ sink = ltn12.sink.table(resultChunks),
+ method = 'POST',
+ headers = { ['content-type']='application/json-rpc', ['content-length']=string.len(jsonRequest) },
+ source = ltn12.source.string(jsonRequest)
+ }
+ )
+ httpResponse = table.concat(resultChunks)
+ -- Check the http response code
+ if (code~=200) then
+ return nil, "HTTP ERROR: " .. code
+ end
+ -- And decode the httpResponse and check the JSON RPC result code
+ result = json.decode( httpResponse )
+ if result.result then
+ return result.result, nil
+ else
+ return nil, result.error
+ end
+end
diff --git a/graphics/mol2chemfig/mol2chemfig-doc.pdf b/graphics/mol2chemfig/mol2chemfig-doc.pdf
new file mode 100644
index 0000000000..e6556bcd62
--- /dev/null
+++ b/graphics/mol2chemfig/mol2chemfig-doc.pdf
Binary files differ
diff --git a/graphics/mol2chemfig/sampledoc/README b/graphics/mol2chemfig/sampledoc/README_SAMPLEDOC
index 68f0b38d61..68f0b38d61 100644
--- a/graphics/mol2chemfig/sampledoc/README
+++ b/graphics/mol2chemfig/sampledoc/README_SAMPLEDOC
diff --git a/graphics/mol2chemfig/sampledoc/fmn.mol b/graphics/mol2chemfig/sampledoc/fmn.mol
new file mode 100644
index 0000000000..7ddf431290
--- /dev/null
+++ b/graphics/mol2chemfig/sampledoc/fmn.mol
@@ -0,0 +1,71 @@
+
+ Marvin 09131216232D
+
+ 31 33 0 0 0 0 999 V2000
+ -0.8545 -2.2393 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -1.5689 -2.6518 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -1.5689 -3.4768 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -0.8545 -3.8893 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -0.1400 -3.4768 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -0.1400 -2.6518 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 0.5745 -2.2393 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
+ 0.5745 -3.8893 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
+ 1.2889 -3.4768 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 1.2889 -2.6518 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.0034 -2.2393 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.0034 -3.8893 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.7179 -3.4768 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.7179 -2.6518 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 0.5745 -1.4143 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 0.1620 -0.6998 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 0.5745 0.0147 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 0.1620 0.7291 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 0.5745 1.4436 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -0.6630 -0.6998 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 1.3995 0.0147 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ -0.6630 0.7291 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 1.3995 1.4436 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.2245 1.4436 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.0495 1.4436 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.2245 0.6186 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
+ 2.2245 2.2686 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
+ -2.2834 -2.2393 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -2.2834 -3.8893 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.0034 -4.7143 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.4323 -2.2393 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 2 1 0 0 0 0
+ 1 6 2 0 0 0 0
+ 2 3 2 0 0 0 0
+ 3 4 1 0 0 0 0
+ 4 5 2 0 0 0 0
+ 7 6 1 0 0 0 0
+ 6 5 1 0 0 0 0
+ 5 8 1 0 0 0 0
+ 7 10 1 0 0 0 0
+ 8 9 1 0 0 0 0
+ 11 10 2 0 0 0 0
+ 10 9 1 0 0 0 0
+ 9 12 1 0 0 0 0
+ 11 14 1 0 0 0 0
+ 12 13 1 0 0 0 0
+ 13 14 1 0 0 0 0
+ 7 15 1 0 0 0 0
+ 15 16 1 0 0 0 0
+ 16 17 1 0 0 0 0
+ 17 18 1 0 0 0 0
+ 18 19 1 0 0 0 0
+ 16 20 1 0 0 0 0
+ 17 21 1 0 0 0 0
+ 18 22 1 0 0 0 0
+ 19 23 1 0 0 0 0
+ 23 24 1 0 0 0 0
+ 24 25 2 0 0 0 0
+ 24 26 1 0 0 0 0
+ 24 27 1 0 0 0 0
+ 2 28 1 0 0 0 0
+ 3 29 1 0 0 0 0
+ 12 30 2 0 0 0 0
+ 14 31 2 0 0 0 0
+M CHG 2 26 -1 27 -1
+M RAD 1 9 2
+M END
diff --git a/graphics/mol2chemfig/sampledoc/mol2chemfig.sty b/graphics/mol2chemfig/sampledoc/mol2chemfig.sty
deleted file mode 100644
index 2de1613f91..0000000000
--- a/graphics/mol2chemfig/sampledoc/mol2chemfig.sty
+++ /dev/null
@@ -1,236 +0,0 @@
-% auxiliary package for mol2chemfig
-\ProvidesPackage{mol2chemfig}[2014/03/24 v1.4]
-
-\RequirePackage{xcolor, chemfig, twoopt, ifmtarg}
-\usetikzlibrary{decorations}
-
-% \setbondstyle is defined by chemfig. Here, we wrap it
-% in order to also save the bond style in a tikz key.
-\let\mcf@setbondstyle\setbondstyle
-\renewcommand{\setbondstyle}[1]{%
- \mcf@setbondstyle{#1}%
- \tikzset{mcfbond/.style={#1}}%
-}
-
-% this macro (by Christian Tellechea) draws circles in aromatic rings.
-\def\mcfcringle#1{%
-\tikz\draw[mcfbond](0,0)circle(\CF@atom@sep*#1*0.66667*\CF@cycle@inraduiscoeff);}
-
-% auxiliary macros for rendering double and triple bonds
-
-% tikz decoration to render parallel bond strokes
-\pgfdeclaredecoration{mcfsecondstroke}{initial}{
- \state{initial}[width=\pgfdecoratedpathlength-1sp]{
- \pgfmoveto{\pgfpointorigin}
- }
- \state{final}{
- \pgflineto{\pgfpointorigin}
- }
-}
-
-% the complete sines definition is taken from http://tex.stackexchange.com/questions/25678/
-\pgfdeclaredecoration{complete sines}{initial}
-{
- \state{initial}[
- width=+0pt,
- next state=sine,
- persistent precomputation={\pgfmathsetmacro\matchinglength{
- \pgfdecoratedinputsegmentlength / int(\pgfdecoratedinputsegmentlength/\pgfdecorationsegmentlength)}
- \setlength{\pgfdecorationsegmentlength}{\matchinglength pt}
- }] {}
- \state{sine}[width=\pgfdecorationsegmentlength]{
- \pgfpathsine{\pgfpoint{0.25\pgfdecorationsegmentlength}{0.5\pgfdecorationsegmentamplitude}}
- \pgfpathcosine{\pgfpoint{0.25\pgfdecorationsegmentlength}{-0.5\pgfdecorationsegmentamplitude}}
- \pgfpathsine{\pgfpoint{0.25\pgfdecorationsegmentlength}{-0.5\pgfdecorationsegmentamplitude}}
- \pgfpathcosine{\pgfpoint{0.25\pgfdecorationsegmentlength}{0.5\pgfdecorationsegmentamplitude}}
-}
- \state{final}{}
-}
-
-% color definitions
-\colorlet{mcfbgcolor}{white} % adjust when drawing on a non-white canvas
-\colorlet{mcfpusharrowcolor}{black}
-\colorlet{mcfatomnocolor}{blue}
-
-\tikzset{ % set styles
- % wavy bonds. Slightly modified from http://www.texdev.net/tag/chemfig/
- mcfwavy/.style =
- {
- decorate,
- decoration =
- {
- complete sines,
- post length = 0 pt,
- pre length = 0 pt,
- % Use chemfig's atom spacing
- segment length = \the\dimexpr\csname CF@atom@sep\endcsname/6\relax,
- amplitude = \the\dimexpr\csname CF@atom@sep\endcsname/10\relax
- }
- },
- % this style is used by the \mcfelmove macro
- mcfpusharrow/.style = {
- ->,
- mcfpusharrowcolor,
- >=stealth,
- shorten <=3pt,
- shorten >=2pt,
- preaction={draw=mcfbgcolor, -,line width=1.5pt}
- },
- %
- mcfbond/.style = {}, % the chemfig default bond style is empty, too.
- %
- % one bond crossing before another - gets a white backdrop
- % as wide as doublesep
- mcfbgcolor/.style={white},
- %
- mcfx/.style 2 args={%
- preaction={
- draw,
- mcfbgcolor,
- line width=\CF@double@sep,
- shorten <= {#1*\CF@double@sep/100},
- shorten >= {#2*\CF@double@sep/100}
- },
- mcfbond
- },
- %
- mcfcrossbond/.style={% for backwards compatibility only
- mcfx={100}{100}
- },
- %
- secondbond/.style 2 args={
- shorten <= {#1*\CF@double@sep/100},
- shorten >= {#2*\CF@double@sep/100},
- mcfbond
- },
- %
- secondfgbond/.style 2 args={
- preaction={draw,-,mcfbgcolor,line width=\CF@double@sep},
- secondbond={#1}{#2}
- },
- %
- secondleft/.style 2 args={
- secondbond={#1}{#2},
- decoration={mcfsecondstroke,raise=\CF@double@sep},
- decorate
- },
- %
- secondright/.style 2 args={
- secondbond={#1}{#2},
- decoration={mcfsecondstroke,raise=-\CF@double@sep},
- decorate
- },
- %
- secondfgleft/.style 2 args={
- secondfgbond={#1}{#2},
- decoration={mcfsecondstroke,raise=\CF@double@sep},
- decorate
- },
- %
- secondfgright/.style 2 args={
- secondfgbond={#1}{#2},
- decoration={mcfsecondstroke,raise=-\CF@double@sep},
- decorate
- },
- %
- dbl/.style 2 args={
- preaction={draw,secondleft={#1}{#2}}
- },
- %
- dbr/.style 2 args={
- preaction={draw,secondright={#1}{#2}}
- },
- %
- trpl/.style 2 args={
- preaction={draw,secondleft={#1}{#2}},
- preaction={draw,secondright={#1}{#2}}
- },
- %
- dblx/.style n args={4}{
- preaction={draw,secondfgleft={#1}{#2}},
- mcfx={#3}{#4}
- },
- %
- dbrx/.style n args={4}{
- preaction={draw,secondfgright={#1}{#2}},
- mcfx={#3}{#4}
- },
- %
- trplx/.style n args={4}{
- preaction={draw,secondfgleft={#1}{#2}},
- preaction={draw,secondfgright={#1}{#2}},
- mcfx={#3}{#4}
- },
- %
- drh/.style={dbr={58}{58}},
- dlh/.style={dbl={58}{58}},
- drhs/.style={dbr={58}{0}},
- dlhs/.style={dbl={58}{0}},
- drhe/.style={dbr={0}{58}},
- dlhe/.style={dbl={0}{58}},
- drn/.style={dbr={0}{0}},
- dln/.style={dbl={0}{0}}
-}
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Conveniences for drawing push arrows
-% the \mcfelmove command is adapted from the
-% myChemistry package by Clemens Niederberger
-
-\newcommand{\mcfelmove}[5][]{%
-\node at (0,0) {% dummy wrapper node
-\chemmove{\draw[mcfpusharrow,#1](#2).. controls +(#3) and +(#5)..(#4);%
-}};}
-
-% and, since the most common use for tikz code
-% is arrow shortening and lengthening: a command streamlined for that.
-
-\newcommandtwoopt{\mcfpush}[6][][]{% we use empties to keep same defaults
-\@ifmtarg{#2}{
- \@ifmtarg{#1}{\mcfelmove{#3}{#4}{#5}{#6}}
- {\mcfelmove[shorten <=#1]{#3}{#4}{#5}{#6}}
-}{% #2 not empty
- \@ifmtarg{#1}{\mcfelmove[shorten >=#2]{#3}{#4}{#5}{#6}}
- {\mcfelmove[shorten <=#1, shorten >=#2]{#3}{#4}{#5}{#6}}
-}}
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Stacking atoms horizontally and vertically
-\newlength{\mcfvspace}
-\setlength{\mcfvspace}{1.5pt}
-
-\newcommand{\mcfabove}[2]{\chemabove[\mcfvspace]{#1}{#2}}
-\newcommand{\mcfbelow}[2]{\chembelow[\mcfvspace]{#1}{#2}}
-
-\newlength{\mcf@boxwidth}
-\newlength{\mcf@boxheight}
-
-\newcommand{\mcf@box}[3][l]{
-\settowidth{\mcf@boxwidth}{\printatom{#2}}
-\settoheight{\mcf@boxheight}{\printatom{#2}}
-\makebox[\mcf@boxwidth][#1]{\raisebox{0pt}[\mcf@boxheight][0pt]{\printatom{#3}}}}
-
-\newcommand{\mcfleft}[2]{\mcf@box[r]{#2}{#1#2}}
-\newcommand{\mcfright}[2]{\mcf@box{#1}{#1#2}}
-
-\newcommand{\mcfaboveright}[3]{\mcfabove{#1}{\mcf@box{#2}{#2#3}}}
-\newcommand{\mcfbelowright}[3]{\mcfbelow{#1}{\mcf@box{#2}{#2#3}}}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Formatting of charges and atom numbers
-
-% Charges - could for example be defined as \oplus and \ominus
-\newcommand{\mcfplus}{+}
-\newcommand{\mcfminus}{-}
-
-% atom numbers (used when option atom-numbers is selected)
-\newcommand{\mcfatomno}[1]%
-{\raisebox{2pt}{\color{mcfatomnocolor}{\ensuremath{\mathsf{_{#1}}}}}}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% a little help with direct processing of mol2chemfig commands
-\newcommand{\mcfinput}[1]{\@@input|"mol2chemfig #1"}
-
-
diff --git a/graphics/mol2chemfig/sampledoc/penicilling.mol b/graphics/mol2chemfig/sampledoc/penicilling.mol
new file mode 100644
index 0000000000..b46719303f
--- /dev/null
+++ b/graphics/mol2chemfig/sampledoc/penicilling.mol
@@ -0,0 +1,53 @@
+
+ Marvin 03280815032D
+
+ 23 25 0 0 0 0 999 V2000
+ 7.6200 1.0703 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0
+ 5.4214 -0.5975 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 7.3229 -1.6623 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 8.6818 -1.2206 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 4.7022 0.1686 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ 6.8353 -0.0096 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
+ 5.4214 1.4034 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
+ 6.8353 0.8154 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 8.1048 0.4029 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 7.6200 -0.2646 0.0000 C 0 0 2 0 0 0 0 0 0 0 0 0
+ 6.0035 0.8188 0.0000 C 0 0 1 0 0 0 0 0 0 0 0 0
+ 6.0035 -0.0130 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 8.7723 0.8878 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 8.7723 -0.0820 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 7.8749 -1.0491 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 4.7053 0.9936 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.9925 1.4088 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.2764 0.9991 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.5636 1.4143 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 3.2733 0.1741 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 1.8475 1.0045 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 2.5573 -0.2357 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 1.8444 0.1796 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 8 1 0 0 0 0
+ 1 9 1 0 0 0 0
+ 2 12 2 0 0 0 0
+ 3 15 1 0 0 0 0
+ 4 15 2 0 0 0 0
+ 5 16 2 0 0 0 0
+ 6 8 1 0 0 0 0
+ 6 10 1 0 0 0 0
+ 6 12 1 0 0 0 0
+ 11 7 1 1 0 0 0
+ 7 16 1 0 0 0 0
+ 8 11 1 0 0 0 0
+ 9 10 1 0 0 0 0
+ 9 13 1 0 0 0 0
+ 9 14 1 0 0 0 0
+ 10 15 1 6 0 0 0
+ 11 12 1 0 0 0 0
+ 16 17 1 0 0 0 0
+ 17 18 1 0 0 0 0
+ 18 19 1 0 0 0 0
+ 18 20 2 0 0 0 0
+ 19 21 2 0 0 0 0
+ 20 22 1 0 0 0 0
+ 21 23 1 0 0 0 0
+ 22 23 2 0 0 0 0
+M END
diff --git a/graphics/mol2chemfig/sampledoc/plp.mol b/graphics/mol2chemfig/sampledoc/plp.mol
new file mode 100644
index 0000000000..09f686e869
--- /dev/null
+++ b/graphics/mol2chemfig/sampledoc/plp.mol
@@ -0,0 +1,48 @@
+
+ Marvin 09131213202D
+
+ 21 21 0 0 0 0 999 V2000
+ -3.2411 0.2063 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -3.9555 -0.2062 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -3.9555 -1.0313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -3.2411 -1.4438 0.0000 N 0 3 0 0 0 0 0 0 0 0 0 0
+ -2.5266 -1.0313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -2.5266 -0.2062 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -1.8121 -1.4438 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -1.8121 0.2063 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
+ -4.6700 0.2063 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -5.3845 -0.2062 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ -6.2095 -0.2062 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0
+ -7.0345 -0.2062 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ -6.2095 -1.0312 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
+ -6.2095 0.6188 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
+ -3.2411 1.0313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -2.5266 1.4438 0.0000 N 0 3 0 0 0 0 0 0 0 0 0 0
+ -2.5266 2.2688 0.0000 C 0 5 0 0 0 0 0 0 0 0 0 0
+ -1.8121 2.6813 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -3.2411 2.6813 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -1.8121 3.5063 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ -1.0977 2.2688 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
+ 1 2 1 0 0 0 0
+ 1 6 2 0 0 0 0
+ 2 3 2 0 0 0 0
+ 3 4 1 0 0 0 0
+ 4 5 2 0 0 0 0
+ 5 6 1 0 0 0 0
+ 5 7 1 0 0 0 0
+ 6 8 1 0 0 0 0
+ 2 9 1 0 0 0 0
+ 9 10 1 0 0 0 0
+ 10 11 1 0 0 0 0
+ 11 12 2 0 0 0 0
+ 11 13 1 0 0 0 0
+ 11 14 1 0 0 0 0
+ 1 15 1 0 0 0 0
+ 15 16 2 0 0 0 0
+ 16 17 1 0 0 0 0
+ 17 18 1 0 0 0 0
+ 17 19 1 0 0 0 0
+ 18 20 2 0 0 0 0
+ 18 21 1 0 0 0 0
+M CHG 7 4 1 8 -1 13 -1 14 -1 16 1 17 -1 21 -1
+M END
diff --git a/graphics/mol2chemfig/sampledoc/plp2.mol b/graphics/mol2chemfig/sampledoc/plp2.mol
new file mode 100644
index 0000000000..8d1459f4fd
--- /dev/null
+++ b/graphics/mol2chemfig/sampledoc/plp2.mol
@@ -0,0 +1,48 @@
+
+ Marvin 09131213192D
+
+ 21 21 0 0 0 0 999 V2000
+ -3.2411 0.2063 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -3.9555 -0.2062 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -3.9555 -1.0313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -3.2411 -1.4438 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
+ -2.5266 -1.0313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -2.5266 -0.2062 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -1.8121 -1.4438 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -1.8121 0.2063 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
+ -4.6700 0.2063 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -5.3845 -0.2062 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ -6.2095 -0.2062 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0
+ -7.0345 -0.2062 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ -6.2095 -1.0312 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
+ -6.2095 0.6188 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
+ -3.2411 1.0313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -2.5266 1.4438 0.0000 N 0 3 0 0 0 0 0 0 0 0 0 0
+ -2.5266 2.2688 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -1.8121 2.6813 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -3.2411 2.6813 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
+ -1.8121 3.5063 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
+ -1.0977 2.2688 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
+ 1 2 1 0 0 0 0
+ 1 6 1 0 0 0 0
+ 2 3 2 0 0 0 0
+ 3 4 1 0 0 0 0
+ 4 5 1 0 0 0 0
+ 5 6 2 0 0 0 0
+ 5 7 1 0 0 0 0
+ 6 8 1 0 0 0 0
+ 2 9 1 0 0 0 0
+ 9 10 1 0 0 0 0
+ 10 11 1 0 0 0 0
+ 11 12 2 0 0 0 0
+ 11 13 1 0 0 0 0
+ 11 14 1 0 0 0 0
+ 1 15 2 0 0 0 0
+ 15 16 1 0 0 0 0
+ 16 17 2 0 0 0 0
+ 17 18 1 0 0 0 0
+ 17 19 1 0 0 0 0
+ 18 20 2 0 0 0 0
+ 18 21 1 0 0 0 0
+M CHG 5 8 -1 13 -1 14 -1 16 1 21 -1
+M END
diff --git a/graphics/mol2chemfig/sampledoc/plp3.tex b/graphics/mol2chemfig/sampledoc/plp3.tex
new file mode 100644
index 0000000000..074af95524
--- /dev/null
+++ b/graphics/mol2chemfig/sampledoc/plp3.tex
@@ -0,0 +1,45 @@
+\definesubmol{plp3}{
+ % 7
+ -[:150]% 5
+ %% -[:210]\mcfbelow{N}{H}% 4 - original line
+ % add an electron pair and a handle
+ -[:210]@{atom4}\mcfbelow{\lewis{2,N}}{H}% 4
+ %% -[:150]% 3 - original line bond from N4 to C3
+ -[@{bond3to4}:150]% 3 - bond with named handle inserted
+ %% =_[:90]% 2 - original line bond C3 to C2
+ =_[@{bond2to3}:90]% 2 - bond with named handle inserted
+ (
+ -[:150]% 9
+ -[:210]O% 10
+ -[:180]P% 11
+ (
+ -[:270]\mcfright{O}{^{\mcfminus}}% 13
+ )
+ (
+ -[:90]\mcfright{O}{^{\mcfminus}}% 14
+ )
+ =[:180]O% 12
+ )
+ %% -[:30]% 1 - original line for bond from C1 to C2
+ -[@{bond1to2}:30]% 1 - bond with named handle inserted
+ (
+ %% =[:90]% 15 - original line for bond from C1 to C15
+ =[@{bond1to15}:90]% 15 - bond with named handle inserted
+ %% -[:30,,,1]NH^{\mcfplus}% 16 - original line
+ -[@{bond15to16}:30,,,1]NH^{\mcfplus}% 16 - handle inserted
+ =[:90,,1]% 17
+ (
+ -[:150]% 19
+ )
+ -[:30]% 18
+ (
+ -[:330]\mcfright{O}{^{\mcfminus}}% 21
+ )
+ =[:90]O% 20
+ )
+ -[:330]% 6
+ (
+ -[:30]\mcfright{O}{^{\mcfminus}}% 8
+ )
+ =_[:270]% -> 5
+}
diff --git a/graphics/mol2chemfig/sampledoc/plp3highlighted.tex b/graphics/mol2chemfig/sampledoc/plp3highlighted.tex
new file mode 100644
index 0000000000..72abd8f1b9
--- /dev/null
+++ b/graphics/mol2chemfig/sampledoc/plp3highlighted.tex
@@ -0,0 +1,40 @@
+\definesubmol{plp3}{&\makeatletter&
+ % 7
+ -[:150]% 5
+ % add an &{\color{blue}electron pair}& and a &{\color{red}named handle}& to atom 4
+ % -[:210]\mcfbelow{N}{H}% 4 - original line
+ -[:210]&{\color{red}@\{atom4\}}\tb{}mcfbelow\{{\color{blue}\tb{}lewis\{2,N\}}\}\{H\}&% 4
+ -[&\color{red}@\{bond3to4\}&:150]% 3 add named handle to bond
+ =_[&\color{red}@\{bond2to3\}&:90]% 2
+ (
+ -[:150]% 9
+ -[:210]O% 10
+ -[:180]P% 11
+ (
+ -[:270]\mcfright{O}{^{\mcfminus}}% 13
+ )
+ (
+ -[:90]\mcfright{O}{^{\mcfminus}}% 14
+ )
+ =[:180]O% 12
+ )
+ -[&\color{red}@\{bond1to2\}&:30]% 1
+ (
+ =[&\color{red}@\{bond1to15\}&:90]% 15
+ -[&\color{red}@\{bond15to16\}&:30,,,1]NH^{\mcfplus}% 16
+ =[:90,,1]% 17
+ (
+ -[:150]% 19
+ )
+ -[:30]% 18
+ (
+ -[:330]\mcfright{O}{^{\mcfminus}}% 21
+ )
+ =[:90]O% 20
+ )
+ -[:330]% 6
+ (
+ -[:30]\mcfright{O}{^{\mcfminus}}% 8
+ )
+ =_[:270]% -> 5 &\makeatother&
+}
diff --git a/graphics/mol2chemfig/sampledoc/plpmarked.tex b/graphics/mol2chemfig/sampledoc/plpmarked.tex
new file mode 100644
index 0000000000..44179b8272
--- /dev/null
+++ b/graphics/mol2chemfig/sampledoc/plpmarked.tex
@@ -0,0 +1,38 @@
+\definesubmol{plpmarked}{
+ @{plp7}%
+ -[@{plp5-7}:150]@{plp5}%
+ -[@{plp4-5}:210]@{plp4}\mcfbelow{N}{H}%
+ -[@{plp3-4}:150]@{plp3}%
+ -[@{plp2-3}:90,,,,drh]@{plp2}%
+ (
+ -[@{plp2-9}:150]@{plp9}%
+ -[@{plp9-10}:210]@{plp10}O%
+ -[@{plp10-11}:180]@{plp11}P%
+ (
+ -[@{plp11-13}:270]@{plp13}\mcfright{O}{^{\mcfminus}}%
+ )
+ (
+ -[@{plp11-14}:90]@{plp14}\mcfright{O}{^{\mcfminus}}%
+ )
+ =[@{plp11-12}:180]@{plp12}O%
+ )
+ -[@{plp1-2}:30]@{plp1}%
+ (
+ -[@{plp1-6}:330]@{plp6}%
+ (
+ -[@{plp6-8}:30]@{plp8}\mcfright{O}{^{\mcfminus}}%
+ )
+ -[@{plp5-6}:270,,,,drh]% -> 5
+ )
+ -[@{plp1-15}:90,,,,drh]@{plp15}%
+ -[@{plp15-16}:30,,,1]@{plp16}NH^{\mcfplus}%
+ =[@{plp16-17}:90,,1]@{plp17}%
+ (
+ -[@{plp17-19}:150]@{plp19}%
+ )
+ -[@{plp17-18}:30]@{plp18}%
+ (
+ =[@{plp18-20}:90]@{plp20}O%
+ )
+ -[@{plp18-21}:330]@{plp21}\mcfright{O}{^{\mcfminus}}%
+}
diff --git a/graphics/mol2chemfig/sampledoc/sample.pdf b/graphics/mol2chemfig/sampledoc/sample.pdf
index 93c3f5c66a..967be89cbe 100644
--- a/graphics/mol2chemfig/sampledoc/sample.pdf
+++ b/graphics/mol2chemfig/sampledoc/sample.pdf
Binary files differ
diff --git a/graphics/mol2chemfig/sampledoc/sample.tex b/graphics/mol2chemfig/sampledoc/sample.tex
index 28bccc62ca..2c90250803 100644
--- a/graphics/mol2chemfig/sampledoc/sample.tex
+++ b/graphics/mol2chemfig/sampledoc/sample.tex
@@ -29,6 +29,11 @@
\author{}\date{}
+% stop gap as per https://tex.stackexchange.com/questions/165929/semiverbatim-with-tikz-in-beamer/165937#165937
+\makeatletter
+\global\let\tikz@ensure@dollar@catcode=\relax
+\makeatother
+
\begin{document}
\maketitle
diff --git a/graphics/mol2chemfig/sampledoc/weg.pdf b/graphics/mol2chemfig/sampledoc/weg.pdf
new file mode 100644
index 0000000000..6857d9c6ad
--- /dev/null
+++ b/graphics/mol2chemfig/sampledoc/weg.pdf
Binary files differ
diff --git a/graphics/mol2chemfig/sampledoc/weg.tex b/graphics/mol2chemfig/sampledoc/weg.tex
new file mode 100644
index 0000000000..6eab4fff04
--- /dev/null
+++ b/graphics/mol2chemfig/sampledoc/weg.tex
@@ -0,0 +1,210 @@
+\documentclass[11pt,letterpaper]{article}
+
+% the mol2chemfig package requires and loads the chemfig package,
+% which must be installed on your system. chemfig is available
+% through TeXLive, MikTeX or from CTAN.
+\usepackage{ctfix3}
+
+% reduce LaTeX's very wide page margins to 1 inch all around
+\usepackage[margin=1in]{geometry}
+
+% use postscript fonts
+\usepackage{courier,times}
+\usepackage[scaled=0.92]{helvet}
+\usepackage{sansmath}
+
+\usepackage{url,listings,textcomp}
+\newcommand{\tb}{\textbackslash}
+\newcommand{\rarr}{\ensuremath{\rightarrow}}
+
+\lstMakeShortInline{\$}
+
+\lstset{%
+ basicstyle=\ttfamily,
+ showstringspaces=false,
+ escapechar=\&
+}
+
+\title{Sample \LaTeX\ document for \texttt{mol2chemfig}}
+
+\author{}\date{}
+
+% stop gap as per https://tex.stackexchange.com/questions/165929/semiverbatim-with-tikz-in-beamer/165937#165937
+\makeatletter
+\global\let\tikz@ensure@dollar@catcode=\relax
+\makeatother
+
+%\setchemfig{bond style=thick,atom sep=20pt, double bond sep=6pt}
+
+\begin{document}
+
+\maketitle
+
+\noindent This sample document illustrates the use of \texttt{mol2chemfig} in conjunction with the \texttt{chemfig} package. This document should compile as is on any system that has a working installation of the \texttt{chemfig} package. A local installation of the \texttt{mol2chemfig} program is not required to compile it, but it \emph{is} required to run the example commands that were used to generate the code. As an alternative to local installation, you can use the web interface at \url{chimpsky.uwaterloo.ca/mol2chemfig}.
+
+In any case, you will need the \texttt{mol2chemfig} \LaTeX\ package in order to compile the generated \LaTeX\ code. A copy of the package should be in the same directory as this source file.
+
+\section*{The structure of penicillin G}
+
+The \texttt{chemfig} code contained in the file \texttt{penicilling.tex} was generated from the molfile with the command:
+
+\begin{verbatim}
+mol2chemfig -wf penicilling.mol > penicilling.tex
+\end{verbatim}
+
+\noindent With \texttt{chemfig}'s default settings, the structure comes out as follows:
+
+\bigskip
+
+\begin{center}
+\input{penicilling}
+\end{center}
+
+\noindent This is a little bit out of proportion to the surrounding text. We can easily adjust the appearance by tweaking some of the settings provided by \texttt{chemfig}:
+
+% these settings adjust the appearance of formulas rendered
+% by chemfig - comment out to see chemfig's defaults
+\setchemfig{
+ cram rectangle=false,
+ cram width=2.5pt,
+ cram dash width=0.4pt,
+ cram dash sep=1pt,
+ atom sep=16pt,
+ bond offset=1pt,
+ double bond sep=2pt
+}
+
+% print atoms with smaller font and in sans-serif
+\renewcommand{\printatom}[1]{\fontsize{8pt}{10pt}\selectfont{\ensuremath{\mathsf{#1}}}}%
+
+\begin{lstlisting}
+% bond styling
+\setchemfig{
+ cram rectangle=false,
+ cram width=1.5ex,
+ cram dash width=1pt,
+ cram dash sep=2pt,
+ atom sep=3em,
+ bond offset=2pt,
+ double bond sep=2pt
+}
+% print atoms with smaller font and in sans-serif
+\renewcommand{\printatom}[1]%
+{\fontsize{8pt}{10pt}\selectfont{\ensuremath{\mathsf{#1}}}}%
+\end{lstlisting}
+
+\noindent With these global settings, the same structure now appears as follows:
+
+\bigskip
+
+\begin{center}
+\input{penicilling}
+\end{center}
+
+\noindent We will leave these settings in effect for the remainder of this document. See the \texttt{chemfig} documentation for additional available settings.
+
+\section*{Incorporating rendered structures into composite graphics}
+
+The \texttt{mol2chemfig} package loads \texttt{chemfig}, which in turn loads the general purpose graphics package \texttt{TikZ}. Through the latter package, we have access to the \texttt{tikzpicture} environment. Here is a \texttt{tikzpicture} that depicts two resonance structures of alanine bound to pyridoxal phosphate:
+
+% load submol definitions - generated with
+% mol2chemfig -f -l plp plp.mol > plp.tex
+% and
+% mol2chemfig -f -l plp2 plp2.mol > plp2.tex
+\input{plp}
+\input{plp2}
+
+\begin{center}
+
+\begin{tikzpicture}%
+[>=stealth, help lines/.style={very thin,draw=black!25}, x=1cm, y=1cm]
+
+% draw grid of help lines - useful while editing
+\draw[help lines] (0,0) grid (12,4);
+
+% place both structures
+\node[anchor=south west, inner sep=10pt] at (0,0) (plp) {\chemfig{!{plp}}};
+\node[anchor=south west, inner sep=10pt] at (7,0) (plp2) {\chemfig{!{plp2}}};
+
+\draw[<->] (plp) -- (plp2);
+
+\end{tikzpicture}
+
+\end{center}
+
+\noindent Note that the $\input$ macro cannot be used inside a $\node$ in the \texttt{tikzpicture} environment. As a workaround, the two structures were rendered as $\submol$ definitions, which were $\input$ outside the \texttt{tikzpicture} environment and then referenced from within the $\node$ macros.
+
+Of course, to be complete and valid, the scheme above should also include arrows that indicate the electron movements underlying the resonance effect. This is possible in \texttt{chemfig} but will in this case require manual annotation of the generated code. So that we can find our way through the code, we can first render the structure to be annotated with atom numbers and display it:
+
+\begin{verbatim}
+mol2chemfig -wn plp2.mol > plpn.tex
+\end{verbatim}
+
+\begin{center}
+\input{plpn}
+\end{center}
+
+This tells us that we need to draw electron movement arrows from nitrogen 4 to the adjacent bond to carbon 3, from bond 2\rarr{}3 to bond 1\rarr{}2, and from bond 1\rarr{}15 to bond 15\rarr{}16.
+
+The mechanism provided by \texttt{chemfig} for drawing push arrows is based on named handles for bonds and atoms. Since version 1.4, \texttt{mol2chemfig} allows you to automatically generate named handles for each atom and bond, using the $--markers$ or $-g$ option:
+
+\begin{verbatim}
+mol2chemfig -f -l plpa -g a plp.mol > plpa.tex
+mol2chemfig -f -l plpb -g b plp2.mol > plpb.tex
+\end{verbatim}
+
+\input{plpa}
+\input{plpb}
+
+This option adds a unique identifier to each atom and to each bond. The option value (\texttt{a} and \texttt{b} in our example) is used as a prefix; this allows to unambiguously reference atoms in multiple molecules in the same drawing. In our first example, atom 3 will be given the marker \lstinline!@{a3}! for atom 3. The bond between atoms 3 and 4 will be labeled with \lstinline!@{a3-4}!; in bond markers, the smaller atom number always precedes the larger one. The generated code now gets a wee bit harsh on the eyeballs:
+
+\lstinputlisting[firstline=1,lastline=6]{plpa.tex}
+\lstinline! ...!
+
+\noindent We can now reference the handles to attach the electron movement arrows. Note that, for this to work, the document has to be processed \emph{twice} by \texttt{pdflatex}, since the commands internally use a PDF overlay mechanism; otherwise, the arrows may be misplaced.
+
+The $\mcfpush$ macro that is used to place the arrows is defined in the \texttt{mol2chemfig} package and is explained in the source code of this document; it is a convenience wrapper around the $\chemmove$ command provided by \texttt{chemfig}.
+
+\begin{center}
+
+\colorlet{mcfpusharrowcolor}{red} % set color for push arrows
+
+\begin{tikzpicture}%
+[>=stealth, help lines/.style={very thin,draw=black!25}, x=1cm, y=1cm]
+
+\draw[help lines] (0,0) grid (12,4);
+
+% place structures
+\node[anchor=south west, inner sep=10pt] at (0,0) (plpa) {\chemfig{!{plpa}}};
+\node[anchor=south west, inner sep=10pt] at (7,0) (plpb) {\chemfig{!{plpb}}};
+
+% horizontal arrow
+\draw[<->] (plpa) -- (plpb);
+
+% enclosing brackets
+\draw[semithick] (0.25,0) -- ++(-0.25,0) -- ++(0,4) -- ++(0.25,0);
+\draw[semithick] (11.75,0) -- ++(0.25,0) -- ++(0,4) -- ++(-0.25,0);
+
+% electron movement arrows. The \mcfpush macro is a convenience
+% wrapper around the \chemmove macro provided by chemfig. The
+% syntax of \mcfpush is
+% \mcfpush{handle1}{angle1:distance1}{handle2}{angle2:distance2}
+% where angles and distances place the control points of the
+% arrow's bezier curve.
+% Two optional arguments specify lengths by which to shorten the
+% arrow at the start and end, respectively. These default to 3pt
+% and 2pt, respectively.
+\mcfpush{a3-4}{70:4mm}{a4}{100:4mm}
+\mcfpush{a1-2}{-30:4mm}{a2-3}{10:4mm}
+\mcfpush{a15-16}{-20:4mm}{a1-15}{0:4mm}
+\mcfpush{a17}{-20:4mm}{a16-17}{-20:4mm}
+
+\mcfpush{b4}{100:4mm}{b3-4}{70:4mm}
+\mcfpush{b2-3}{10:4mm}{b1-2}{-30:4mm}
+\mcfpush[4pt][3pt]{b1-15}{0:4mm}{b15-16}{-20:4mm}
+\mcfpush{b16-17}{-20:4mm}{b17}{-20:4mm}
+\end{tikzpicture}
+
+\end{center}
+
+\end{document} \ No newline at end of file
diff --git a/graphics/mol2chemfig/tex/mol2chemfig.sty b/graphics/mol2chemfig/tex/mol2chemfig.sty
deleted file mode 100644
index 2de1613f91..0000000000
--- a/graphics/mol2chemfig/tex/mol2chemfig.sty
+++ /dev/null
@@ -1,236 +0,0 @@
-% auxiliary package for mol2chemfig
-\ProvidesPackage{mol2chemfig}[2014/03/24 v1.4]
-
-\RequirePackage{xcolor, chemfig, twoopt, ifmtarg}
-\usetikzlibrary{decorations}
-
-% \setbondstyle is defined by chemfig. Here, we wrap it
-% in order to also save the bond style in a tikz key.
-\let\mcf@setbondstyle\setbondstyle
-\renewcommand{\setbondstyle}[1]{%
- \mcf@setbondstyle{#1}%
- \tikzset{mcfbond/.style={#1}}%
-}
-
-% this macro (by Christian Tellechea) draws circles in aromatic rings.
-\def\mcfcringle#1{%
-\tikz\draw[mcfbond](0,0)circle(\CF@atom@sep*#1*0.66667*\CF@cycle@inraduiscoeff);}
-
-% auxiliary macros for rendering double and triple bonds
-
-% tikz decoration to render parallel bond strokes
-\pgfdeclaredecoration{mcfsecondstroke}{initial}{
- \state{initial}[width=\pgfdecoratedpathlength-1sp]{
- \pgfmoveto{\pgfpointorigin}
- }
- \state{final}{
- \pgflineto{\pgfpointorigin}
- }
-}
-
-% the complete sines definition is taken from http://tex.stackexchange.com/questions/25678/
-\pgfdeclaredecoration{complete sines}{initial}
-{
- \state{initial}[
- width=+0pt,
- next state=sine,
- persistent precomputation={\pgfmathsetmacro\matchinglength{
- \pgfdecoratedinputsegmentlength / int(\pgfdecoratedinputsegmentlength/\pgfdecorationsegmentlength)}
- \setlength{\pgfdecorationsegmentlength}{\matchinglength pt}
- }] {}
- \state{sine}[width=\pgfdecorationsegmentlength]{
- \pgfpathsine{\pgfpoint{0.25\pgfdecorationsegmentlength}{0.5\pgfdecorationsegmentamplitude}}
- \pgfpathcosine{\pgfpoint{0.25\pgfdecorationsegmentlength}{-0.5\pgfdecorationsegmentamplitude}}
- \pgfpathsine{\pgfpoint{0.25\pgfdecorationsegmentlength}{-0.5\pgfdecorationsegmentamplitude}}
- \pgfpathcosine{\pgfpoint{0.25\pgfdecorationsegmentlength}{0.5\pgfdecorationsegmentamplitude}}
-}
- \state{final}{}
-}
-
-% color definitions
-\colorlet{mcfbgcolor}{white} % adjust when drawing on a non-white canvas
-\colorlet{mcfpusharrowcolor}{black}
-\colorlet{mcfatomnocolor}{blue}
-
-\tikzset{ % set styles
- % wavy bonds. Slightly modified from http://www.texdev.net/tag/chemfig/
- mcfwavy/.style =
- {
- decorate,
- decoration =
- {
- complete sines,
- post length = 0 pt,
- pre length = 0 pt,
- % Use chemfig's atom spacing
- segment length = \the\dimexpr\csname CF@atom@sep\endcsname/6\relax,
- amplitude = \the\dimexpr\csname CF@atom@sep\endcsname/10\relax
- }
- },
- % this style is used by the \mcfelmove macro
- mcfpusharrow/.style = {
- ->,
- mcfpusharrowcolor,
- >=stealth,
- shorten <=3pt,
- shorten >=2pt,
- preaction={draw=mcfbgcolor, -,line width=1.5pt}
- },
- %
- mcfbond/.style = {}, % the chemfig default bond style is empty, too.
- %
- % one bond crossing before another - gets a white backdrop
- % as wide as doublesep
- mcfbgcolor/.style={white},
- %
- mcfx/.style 2 args={%
- preaction={
- draw,
- mcfbgcolor,
- line width=\CF@double@sep,
- shorten <= {#1*\CF@double@sep/100},
- shorten >= {#2*\CF@double@sep/100}
- },
- mcfbond
- },
- %
- mcfcrossbond/.style={% for backwards compatibility only
- mcfx={100}{100}
- },
- %
- secondbond/.style 2 args={
- shorten <= {#1*\CF@double@sep/100},
- shorten >= {#2*\CF@double@sep/100},
- mcfbond
- },
- %
- secondfgbond/.style 2 args={
- preaction={draw,-,mcfbgcolor,line width=\CF@double@sep},
- secondbond={#1}{#2}
- },
- %
- secondleft/.style 2 args={
- secondbond={#1}{#2},
- decoration={mcfsecondstroke,raise=\CF@double@sep},
- decorate
- },
- %
- secondright/.style 2 args={
- secondbond={#1}{#2},
- decoration={mcfsecondstroke,raise=-\CF@double@sep},
- decorate
- },
- %
- secondfgleft/.style 2 args={
- secondfgbond={#1}{#2},
- decoration={mcfsecondstroke,raise=\CF@double@sep},
- decorate
- },
- %
- secondfgright/.style 2 args={
- secondfgbond={#1}{#2},
- decoration={mcfsecondstroke,raise=-\CF@double@sep},
- decorate
- },
- %
- dbl/.style 2 args={
- preaction={draw,secondleft={#1}{#2}}
- },
- %
- dbr/.style 2 args={
- preaction={draw,secondright={#1}{#2}}
- },
- %
- trpl/.style 2 args={
- preaction={draw,secondleft={#1}{#2}},
- preaction={draw,secondright={#1}{#2}}
- },
- %
- dblx/.style n args={4}{
- preaction={draw,secondfgleft={#1}{#2}},
- mcfx={#3}{#4}
- },
- %
- dbrx/.style n args={4}{
- preaction={draw,secondfgright={#1}{#2}},
- mcfx={#3}{#4}
- },
- %
- trplx/.style n args={4}{
- preaction={draw,secondfgleft={#1}{#2}},
- preaction={draw,secondfgright={#1}{#2}},
- mcfx={#3}{#4}
- },
- %
- drh/.style={dbr={58}{58}},
- dlh/.style={dbl={58}{58}},
- drhs/.style={dbr={58}{0}},
- dlhs/.style={dbl={58}{0}},
- drhe/.style={dbr={0}{58}},
- dlhe/.style={dbl={0}{58}},
- drn/.style={dbr={0}{0}},
- dln/.style={dbl={0}{0}}
-}
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Conveniences for drawing push arrows
-% the \mcfelmove command is adapted from the
-% myChemistry package by Clemens Niederberger
-
-\newcommand{\mcfelmove}[5][]{%
-\node at (0,0) {% dummy wrapper node
-\chemmove{\draw[mcfpusharrow,#1](#2).. controls +(#3) and +(#5)..(#4);%
-}};}
-
-% and, since the most common use for tikz code
-% is arrow shortening and lengthening: a command streamlined for that.
-
-\newcommandtwoopt{\mcfpush}[6][][]{% we use empties to keep same defaults
-\@ifmtarg{#2}{
- \@ifmtarg{#1}{\mcfelmove{#3}{#4}{#5}{#6}}
- {\mcfelmove[shorten <=#1]{#3}{#4}{#5}{#6}}
-}{% #2 not empty
- \@ifmtarg{#1}{\mcfelmove[shorten >=#2]{#3}{#4}{#5}{#6}}
- {\mcfelmove[shorten <=#1, shorten >=#2]{#3}{#4}{#5}{#6}}
-}}
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Stacking atoms horizontally and vertically
-\newlength{\mcfvspace}
-\setlength{\mcfvspace}{1.5pt}
-
-\newcommand{\mcfabove}[2]{\chemabove[\mcfvspace]{#1}{#2}}
-\newcommand{\mcfbelow}[2]{\chembelow[\mcfvspace]{#1}{#2}}
-
-\newlength{\mcf@boxwidth}
-\newlength{\mcf@boxheight}
-
-\newcommand{\mcf@box}[3][l]{
-\settowidth{\mcf@boxwidth}{\printatom{#2}}
-\settoheight{\mcf@boxheight}{\printatom{#2}}
-\makebox[\mcf@boxwidth][#1]{\raisebox{0pt}[\mcf@boxheight][0pt]{\printatom{#3}}}}
-
-\newcommand{\mcfleft}[2]{\mcf@box[r]{#2}{#1#2}}
-\newcommand{\mcfright}[2]{\mcf@box{#1}{#1#2}}
-
-\newcommand{\mcfaboveright}[3]{\mcfabove{#1}{\mcf@box{#2}{#2#3}}}
-\newcommand{\mcfbelowright}[3]{\mcfbelow{#1}{\mcf@box{#2}{#2#3}}}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Formatting of charges and atom numbers
-
-% Charges - could for example be defined as \oplus and \ominus
-\newcommand{\mcfplus}{+}
-\newcommand{\mcfminus}{-}
-
-% atom numbers (used when option atom-numbers is selected)
-\newcommand{\mcfatomno}[1]%
-{\raisebox{2pt}{\color{mcfatomnocolor}{\ensuremath{\mathsf{_{#1}}}}}}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% a little help with direct processing of mol2chemfig commands
-\newcommand{\mcfinput}[1]{\@@input|"mol2chemfig #1"}
-
-
diff --git a/graphics/pgf/contrib/dynkin-diagrams/DoneTwoElBendy.tex b/graphics/pgf/contrib/dynkin-diagrams/DoneTwoElBendy.tex
new file mode 100644
index 0000000000..b878b676b8
--- /dev/null
+++ b/graphics/pgf/contrib/dynkin-diagrams/DoneTwoElBendy.tex
@@ -0,0 +1,5 @@
+\begin{dynkinDiagram}[ply=4]{D}[1]%
+{****.*****.*****}
+ \dynkinFold[bend right=90]{1}{13}
+ \dynkinFold[bend right=90]{0}{14}
+\end{dynkinDiagram}
diff --git a/graphics/pgf/contrib/dynkin-diagrams/DoneTwoElStraight.tex b/graphics/pgf/contrib/dynkin-diagrams/DoneTwoElStraight.tex
new file mode 100644
index 0000000000..f74b7f7b19
--- /dev/null
+++ b/graphics/pgf/contrib/dynkin-diagrams/DoneTwoElStraight.tex
@@ -0,0 +1,6 @@
+\begin{dynkinDiagram}[ply=4]{D}[1]%
+{****.*****.*****}
+ \dynkinFold{0}{1}
+ \dynkinFold{1}{13}
+ \dynkinFold{13}{14}
+\end{dynkinDiagram}
diff --git a/graphics/pgf/contrib/dynkin-diagrams/EulerProducts.tex b/graphics/pgf/contrib/dynkin-diagrams/EulerProducts.tex
new file mode 100644
index 0000000000..f087ce48b6
--- /dev/null
+++ b/graphics/pgf/contrib/dynkin-diagrams/EulerProducts.tex
@@ -0,0 +1,61 @@
+\tikzset{/Dynkin diagram,ordering=Dynkin,label macro/.code={\alpha_{#1}}}
+\newcounter{EPNo}
+\setcounter{EPNo}{0}
+\NewDocumentCommand\EP{smmmm}%
+{%
+\stepcounter{EPNo}\roman{EPNo}. &
+\def\eL{.6cm}
+\IfStrEqCase{#2}%
+{%
+{D}{\gdef\eL{1cm}}%
+{E}{\gdef\eL{.75cm}}%
+{F}{\gdef\eL{.35cm}}%
+{G}{\gdef\eL{.35cm}}%
+}%
+\tikzset{/Dynkin diagram,edge length=\eL}
+\IfBooleanTF{#1}%
+{\dynkin[backwards,labels*={#4},labels={#5}]{#2}{#3}}
+{\dynkin[labels*={#4},labels={#5}]{#2}{#3}}
+\\
+}%
+\begin{longtable}{MM}
+\caption{Dynkin diagrams from Euler products \cite{Langlands:1967}}\\
+\endfirsthead
+\caption{\dots continued}\\
+\endhead
+\multicolumn{2}{c}{continued \dots}\\
+\endfoot
+\endlastfoot
+\EP{A}{***.**}{1,1,1,1,1}{,1,2,n-1,n}
+\EP{A}{***.**}{1,1,1,1,1}{1,2,n-1,n}
+\EP{A}{**.***.*}{1,1,1,1,1,1}{1,2,m-1,,m,n}
+\EP{B}{**.***}{2,2,2,2,1}{1,2,n-1,n}
+\EP*{B}{***.**}{2,2,2,2,1}{n,n-1,2,1,}
+\EP{C}{**.***}{1,1,1,1,2}{1,2,n-1,}
+\EP*{C}{***.**}{1,1,1,1,2}{n,n-1,2,1,}
+\EP{D}{**.****}{1,1,1,1,1,1}{1,2,n-2,n-1,n}
+\EP{D}{**.****}{1,1,1,1,1,1}{1,2,n-2,n-1,n}
+\EP{E}{6}{1,1,1,1,1,1}{1,...,5}
+\EP*{E}{7}{1,1,1,1,1,1,1}{6,...,1}
+\EP{E}{7}{1,1,1,1,1,1,1}{1,...,6}
+\EP*{E}{8}{1,1,1,1,1,1,1,1}{7,...,1}
+\EP{E}{8}{1,1,1,1,1,1,1,1}{1,...,7}
+\EP{G}{2}{1,3}{,1}
+\EP{G}{2}{1,3}{1}
+\EP{B}{**.*.**}{2,2,2,2,1}{,1,2,n-1,n}
+\EP{F}{4}{1,1,2,2}{,3,2,1}
+\EP{C}{3}{1,1,2}{,2,1}
+\EP{C}{**.***}{1,1,1,1,2}{,1,n-2,n-1,n}
+\EP*{B}{3}{2,2,1}{1,2}
+\EP{F}{4}{1,1,2,2}{1,2,3}
+\EP{D}{**.****}{1,1,1,1,1,1}{1,2,n-2,n-2,n,n}
+\EP{E}{6}{1,1,1,1,1,1}{1,2,3,4,,5}
+\EP{E}{6}{1,1,1,1,1,1}{1,2,3,5,,4}
+\EP*{E}{7}{1,1,1,1,1,1,1}{,5,...,1,6}
+\EP*{E}{7}{1,1,1,1,1,1,1}{,6,4,3,2,1,5}
+\EP*{E}{8}{1,1,1,1,1,1,1,1}{,6,...,1,7}
+\EP*{E}{8}{1,1,1,1,1,1,1,1}{,7,5,4,3,2,1,6}
+\EP*{E}{7}{1,1,1,1,1,1,1}{5,...,1,,6}
+\EP*{E}{7}{1,1,1,1,1,1,1}{1,...,5,,6}
+\EP*{E}{8}{1,1,1,1,1,1,1,1}{6,...,1,,7}
+\end{longtable}
diff --git a/graphics/pgf/contrib/dynkin-diagrams/README b/graphics/pgf/contrib/dynkin-diagrams/README
index cdd04fdf1f..94427be9e2 100644
--- a/graphics/pgf/contrib/dynkin-diagrams/README
+++ b/graphics/pgf/contrib/dynkin-diagrams/README
@@ -2,9 +2,9 @@ ___________________________________
Dynkin diagrams
- v3.141592
+ v3.1415926
- 24 January 2019
+ 25 November 2019
___________________________________
Authors : Ben McKay
@@ -16,6 +16,9 @@ Licence : Released under the LaTeX Project Public License v1.3c or
----------------------------------------------------------------------
Draws Dynkin di­a­grams in LaTeX doc­u­ments, us­ing the TikZ pack­age.
-Version 3.141592 fixes a rarely encountered problem with changing the default root marker and default affine root marker simultaneously, and smooths the ceref style indefinite edges.
+Version 3.1415926 fixes problems with
+(1) horizontal alignment of labels of varying heights,
+(2) text styles being ignored.
+
diff --git a/graphics/pgf/contrib/dynkin-diagrams/borovoi.tex b/graphics/pgf/contrib/dynkin-diagrams/borovoi.tex
new file mode 100644
index 0000000000..f0664d2207
--- /dev/null
+++ b/graphics/pgf/contrib/dynkin-diagrams/borovoi.tex
@@ -0,0 +1,15 @@
+\tikzset{big arrow/.style={
+ -Stealth,line cap=round,line width=1mm,
+ shorten <=1mm,shorten >=1mm}}
+\newcommand\catholic[2]{\draw[big arrow,green!25!white]
+(root #1) to (root #2);}
+\newcommand\protestant[2]{
+\begin{scope}[transparency group, opacity=.25]
+\draw[big arrow,orange] (root #1) to (root #2);
+\end{scope}}
+\begin{dynkinDiagram}[edge length=1.2cm,
+indefinite edge/.style={thick,loosely dotted},
+labels*={0,1,2,3,\ell-3,\ell-2,\ell-1,\ell}]{D}[1]{}
+\catholic{0}{6}\catholic{1}{7}
+\protestant{7}{0}\protestant{6}{1}
+\end{dynkinDiagram}
diff --git a/graphics/pgf/contrib/dynkin-diagrams/d44.tex b/graphics/pgf/contrib/dynkin-diagrams/d44.tex
new file mode 100644
index 0000000000..482b805fa5
--- /dev/null
+++ b/graphics/pgf/contrib/dynkin-diagrams/d44.tex
@@ -0,0 +1,19 @@
+\tikzset{/Dynkin diagram,edge length=1cm,fold radius=1cm}
+\tikzset{/Dynkin diagram,label macro/.code={\alpha_{#1}},label macro*/.code={\beta_{#1}}}
+\({}^1 D_4\) 4-ply tied straight:
+\begin{dynkinDiagram}[ply=4]{D}[1]%
+{****.*****.*****}
+ \dynkinFold{0}{1}
+ \dynkinFold{1}{13}
+ \dynkinFold{13}{14}
+\dynkinLabelRoots{0,...,14}
+\dynkinLabelRoots*{0,...,14}
+\end{dynkinDiagram}
+\({}^1 D_4\) 4-ply tied bending:
+\begin{dynkinDiagram}[ply=4]{D}[1]%
+{****.*****.*****}
+ \dynkinFold{1}{13}
+ \dynkinFold[bend right=65]{0}{14}
+\dynkinLabelRoots{0,...,14}
+\dynkinLabelRoots*{0,...,14}
+\end{dynkinDiagram}
diff --git a/graphics/pgf/contrib/dynkin-diagrams/dynkin-diagrams.pdf b/graphics/pgf/contrib/dynkin-diagrams/dynkin-diagrams.pdf
deleted file mode 100644
index d28d05f96c..0000000000
--- a/graphics/pgf/contrib/dynkin-diagrams/dynkin-diagrams.pdf
+++ /dev/null
Binary files differ
diff --git a/graphics/pgf/contrib/dynkin-diagrams/dynkin-diagrams.sty b/graphics/pgf/contrib/dynkin-diagrams/dynkin-diagrams.sty
index 32e6c17833..e644e6251e 100644
--- a/graphics/pgf/contrib/dynkin-diagrams/dynkin-diagrams.sty
+++ b/graphics/pgf/contrib/dynkin-diagrams/dynkin-diagrams.sty
@@ -2,7 +2,7 @@
%
% The Dynkin Diagrams package.
%
-% Version 3.141592
+% Version 3.1415926
%
%
% This package draws Dynkin diagrams in LaTeX documents, using the TikZ package.
@@ -18,7 +18,7 @@
%
%
\NeedsTeXFormat{LaTeX2e}[1994/06/01]
-\ProvidesPackage{dynkin-diagrams}[2019/01/24 Dynkin diagrams]
+\ProvidesPackage{dynkin-diagrams}[2019/11/25 Dynkin diagrams]
\RequirePackage{tikz}
\RequirePackage{xstring}
\RequirePackage{xparse}
@@ -39,7 +39,6 @@
fit,
patterns,
shadows}
-
%%%
%%% Application programming interface:
%%% See dynkin-diagrams.tex file for examples of use.
@@ -862,15 +861,11 @@ decoration=
arc (180:90:{\dynkin@fold@radius});%
\ifdynkin@arrows%
\ifdynkin@reverse@arrows%
- \path[/Dynkin diagram,edge,
- -{Computer Modern Rightarrow[\dynkin@arrow@color]},
- ,tips]
+ \path[-{Computer Modern Rightarrow[\dynkin@arrow@color]},tips]
($(\dynkin@root@name \the\@toRoot)$)%
- arc (135:180:{\dynkin@fold@radius});%
+ arc (90:135:{\dynkin@fold@radius});%
\else%
- \path[/Dynkin diagram,edge,
- -{Computer Modern Rightarrow[\dynkin@arrow@color]},
- ,tips]
+ \path[-{Computer Modern Rightarrow[\dynkin@arrow@color]},tips]
($(\dynkin@root@name \the\@fromRoot)$)%
arc (180:135:{\dynkin@fold@radius});%
\fi%
@@ -1159,7 +1154,13 @@ decoration=
\@toRoot=#4%
}%
\begin{scope}[on background layer]%
- \draw[/Dynkin diagram,edge,double,double distance=\dynkin@root@radius,fill=none,#2]%
+ \draw[/Dynkin diagram,
+ edge,
+ double,
+ double distance=\dynkin@root@radius,
+ fill=none,
+ {Straight Barb[length=1pt]}-{Straight Barb[length=1pt]},
+ #2]%
($(\dynkin@root@name \the\@fromRoot)$)%
arc (90:-90:{\dynkin@fold@radius});%
\draw[/Dynkin diagram,edge,fill=none,#2]%
@@ -1712,7 +1713,7 @@ decoration=
reverse arrows/.is if = dynkin@reverse@arrows,
reverse arrows = false,
reverse-arrows/.forward to = /Dynkin diagram/reverse arrows,
- fold style/.style = {solid,draw=black!40,fill=none,line width=\dynkin@root@radius},
+ fold style/.style = {solid,draw=black!40,fill=none,line width=\dynkin@root@radius,{Triangle Cap[]}-{Triangle Cap[]}},
fold-style/.forward to=/Dynkin diagram/fold style/.style,
fold left style/.style = {},
fold-left-style/.forward to=/Dynkin diagram/fold left style/.style,
@@ -1817,7 +1818,6 @@ decoration=
Coxeter=false,
ordering/.store in = \dynkin@ordering,
ordering = Bourbaki,
- text style/.style={scale=.7},
text-style/.forward to=/Dynkin diagram/text style/.style,
label macro/.code = {\regurgitate{#1}},
label-macro/.forward to=/Dynkin diagram/label macro,
@@ -1887,9 +1887,19 @@ decoration=
fill=white,
},
},
+ label height/.style={/tikz/every label/.append style={text height={height("#1"}}},
+ label depth/.style={/tikz/every label/.append style={text depth={depth("#1"}}},
+ text style/.style={/tikz/every label/.append style={#1}},
default/.style = {
+ text style={scale=.7},
label/.is if = dynkin@label@the@roots,
label = false,
+ label height/.default=b,
+ label depth/.default=g,
+ label height,
+ label depth,
+ label-height/.forward to = /Dynkin diagram/label height,
+ label-depth/.forward to = /Dynkin diagram/label depth,
labels = {},
labels* = {},
at/.estore in = \dynkin@current@location,
diff --git a/graphics/pgf/contrib/dynkin-diagrams/dynkin-diagrams.tex b/graphics/pgf/contrib/dynkin-diagrams/dynkin-diagrams.tex
index 6d84d1606d..b11488ffdd 100644
--- a/graphics/pgf/contrib/dynkin-diagrams/dynkin-diagrams.tex
+++ b/graphics/pgf/contrib/dynkin-diagrams/dynkin-diagrams.tex
@@ -1,6 +1,6 @@
\documentclass{amsart}
-\title{The Dynkin diagrams package \\ Version 3.141592}
+\title{The Dynkin diagrams package \\ Version 3.1415926}
\makeatletter
\DeclareRobustCommand{\scotsMc}{\scotsMcx{c}}
@@ -20,16 +20,18 @@
\author{Ben \scotsMc{}Kay}
\address{School of Mathematical Sciences, University College Cork, Cork, Ireland}
\email{b.mckay@ucc.ie}
-\date{24 January 2019}
+\date{25 November 2019}
\usepackage{etex}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenx}
\usepackage{etoolbox}
\usepackage{lmodern}
+\RequirePackage[tt=lining]{cfr-lm}
\usepackage[kerning=true,tracking=true]{microtype}
\usepackage{amsmath}
\usepackage{amsfonts}
+\usepackage{mathtools}
\usepackage{array}
\usepackage{xstring}
\usepackage{longtable}
@@ -65,10 +67,10 @@
\newcommand{\C}[1]{\mathbb{C}^{#1}}
\renewcommand*{\arraystretch}{1.5}
-\NewDocumentCommand\wdtA{}{.7cm}
-\NewDocumentCommand\wdtD{}{3cm}
-\NewDocumentCommand\wdtE{}{6cm}
-\NewDocumentCommand\wdtL{}{3cm}
+\newcommand{\wdtA}{.7cm}
+\newcommand{\wdtD}{3cm}
+\newcommand{\wdtE}{6cm}
+\newcommand{\wdtL}{3cm}
\newcolumntype{A}{@{}>{\columncolor[gray]{.9}$}m{\wdtA}<{$}}
\newcolumntype{B}{@{}>{\columncolor[gray]{.9}}m{\wdtA}}
\newcolumntype{D}{>{\columncolor[gray]{.9}}m{\wdtD}}
@@ -106,8 +108,8 @@
\NewDocumentEnvironment{dynkinTable}{mmm}%
{%
-\RenewDocumentCommand\wdtD{}{#2}
-\RenewDocumentCommand\wdtL{}{#3}
+\renewcommand{\wdtD}{#2}
+\renewcommand{\wdtL}{#3}
\begin{longtable}{ADM}
\caption{#1}\\
\endfirsthead
@@ -150,7 +152,6 @@ before upper={\widowpenalties=3 10000 10000 150}}
\fvset{fontsize=\small}
\begin{document}
-
\maketitle
\begin{center}
\begin{varwidth}{\textwidth}
@@ -158,7 +159,6 @@ before upper={\widowpenalties=3 10000 10000 150}}
\end{varwidth}
\end{center}
-
\setlength{\arrayrulewidth}{1.5pt}
\section{Quick introduction}
@@ -185,7 +185,7 @@ The Dynkin diagram of \(B_3\) is
\end{dynkinDiagram}
\end{tcblisting}
\begin{tcblisting}{title={Inside a \TikZ environment}}
-The baseline controls the vertical alignment:
+Baseline controls vertical alignment:
the Dynkin diagram of \(B_3\) is
\begin{tikzpicture}[baseline=(origin.base)]
\dynkin{B}{3}
@@ -208,6 +208,7 @@ the Dynkin diagram of \(B_3\) is
\end{dynkinTable}
+
\section{Set options globally}
\begin{tcolorbox}[title={Most options set globally \dots}]
@@ -234,6 +235,7 @@ You can also pass options to the package in \verb!\usepackage!.
+
\section{Coxeter diagrams}
\begin{tcblisting}{title={Coxeter diagram option}}
@@ -259,6 +261,7 @@ You can also pass options to the package in \verb!\usepackage!.
\dyn[Coxeter,gonality=n]{I}{}
\end{dynkinTable}
+
\section{Satake diagrams}\label{section:Satake}
\begin{tcblisting}{title={Satake diagrams use the standard name instead of a rank}}
@@ -342,10 +345,10 @@ segment length=1mm,amplitude=.6mm}}}
\section{Labels for the roots}
\begin{tcblisting}{title={Make a macro to assign labels to roots}}
-\dynkin[label,label macro/.code={\alpha_{#1}},edge length=.75cm]{D}{5}
+\dynkin[label,label macro/.code={\alpha_{\mathrlap{#1}}},edge length=.75cm]{D}{5}
\end{tcblisting}
\begin{tcblisting}{title={Labelling several roots}}
-\dynkin[labels={,2,...,5,,7},label macro/.code={\alpha_{#1}}]{A}{7}
+\dynkin[labels={,2,...,5,,7},label macro/.code={\alpha_{\mathrlap#1}}]{A}{7}
\end{tcblisting}
\begin{tcblisting}{title={The \texttt{foreach} notation I}}
\dynkin[labels={1,3,...,7},]{A}{9}
@@ -354,7 +357,7 @@ segment length=1mm,amplitude=.6mm}}}
\dynkin[labels={,\alpha_2,\alpha_...,\alpha_7},]{A}{7}
\end{tcblisting}
\begin{tcblisting}{title={The \texttt{foreach} notation III}}
-\dynkin[label macro/.code={\beta_{#1}},labels={,2,...,7},]{A}{7}
+\dynkin[label macro/.code={\beta_{\mathrlap{#1}}},labels={,2,...,7},]{A}{7}
\end{tcblisting}
\begin{tcblisting}{title={Label the roots individually by root number}}
\dynkin[label]{B}{3}
@@ -364,14 +367,9 @@ segment length=1mm,amplitude=.6mm}}}
\dynkinLabelRoot{2}{\alpha_2}
\end{dynkinDiagram}
\end{tcblisting}
-\begin{tcblisting}{title={Use a text style}}
-\begin{dynkinDiagram}[text/.style={scale=1.2}]{B}{3};
-\dynkinLabelRoot{2}{\alpha_2}
-\end{dynkinDiagram}
-\end{tcblisting}
\begin{tcblisting}{title={Access root labels via TikZ}}
\begin{dynkinDiagram}{B}{3}
-\node[below] at (root 2) {\(\alpha_2\)};
+\node[below] at (root 2) {\(\alpha_{\mathrlap{2}}\)};
\end{dynkinDiagram}
\end{tcblisting}
\begin{tcblisting}{title={Commands to label several roots}}
@@ -387,8 +385,8 @@ segment length=1mm,amplitude=.6mm}}}
\end{tcblisting}
\begin{tcblisting}{title={Labelling several roots and alternates}}
\dynkin[%
-label macro/.code={\alpha_{#1}},
-label macro*/.code={\gamma_{#1}},
+label macro/.code={\alpha_{\mathrlap{#1}}},
+label macro*/.code={\gamma_{\mathrlap{#1}}},
labels={,2,...,5,,7},
labels*={1,3,4,5,6}]{A}{7}
\end{tcblisting}
@@ -399,6 +397,50 @@ labels*={1,3,4,5,6}]{A}{7}
\end{dynkinDiagram}
\end{tcblisting}
+\section{Label subscripts}
+Note the slight improvement that \verb!\mathrlap! makes: the labels are centered on the middle of the letter \(\alpha\), ignoring the space taken up by the subscripts.
+\begin{tcblisting}{title={Label spacing improvement}}
+\dynkin[label,label macro/.code={\alpha_{#1}},edge length=.75cm]{D}{15}
+\par\noindent{}%
+\dynkin[label,label macro/.code={\alpha_{\mathrlap{#1}}},edge length=.75cm]{D}{15}
+\end{tcblisting}
+
+
+\section{Height and depth of labels}
+Labels are set with default maximum height the height of the character \(b\), and default maximum depth the depth of the character \(g\).
+To change these, set \verb!label height! and \verb!label depth!:
+\begin{tcblisting}{title={Change height and dept of characters}}
+\dynkin[labels={a,b,c,d}]{F}{4}
+\dynkin[labels*={a,b,c,d}]{F}{4}
+\dynkin[%
+label macro/.code={\alpha_{\mathrlap{#1}}},
+label macro*/.code={\gamma_{\mathrlap{#1}}},
+label height=$\alpha_1$,
+label depth=$\alpha_1$,
+labels={,2,...,5,,7},
+labels*={1,3,4,5,6}]{A}{7}
+\dynkin[labels={A,B,C,D},label height=$A$,label depth=$A$]{F}{4}
+\dynkin[labels={a^1,b^2,c^3,d^4},label height=$X^X$]{F}{4}
+\end{tcblisting}
+
+\section{Text style for the labels}
+\begin{tcblisting}{title={Use a text style: big and blue}}
+\begin{dynkinDiagram}[text style={scale=1.2,blue},
+edge length=.75cm,
+labels={1,2,n-1,n},
+label macro/.code={\alpha_{\mathrlap{#1}}}
+]{A}{}
+\end{dynkinDiagram}
+\end{tcblisting}
+\begin{tcblisting}{title={Use a text style; font selection is in the label macro}}
+\begin{dynkinDiagram}[text style={scale=1.2,blue},
+edge length=.75cm,
+labels={1,2,n-1,n},
+label macro/.code={\mathbb{A}_{\mathrlap{#1}}}]{A}{}
+\end{dynkinDiagram}
+\end{tcblisting}
+
+
\section{Bracing roots}
\begin{tcblisting}{title={Bracing roots}}
@@ -610,7 +652,7 @@ If you need to repeat a mark, you can give a \emph{single digit} positive intege
\NewDocumentCommand\ClassicalLieSuperalgebras{om}%
{%
\IfValueT{#1}{\tikzset{/Dynkin diagram,root radius=#1}}
-\RenewDocumentCommand\wdtE{}{10cm}
+\renewcommand{\wdtE}{10cm}
\begin{dynkinTable}{Classical Lie superalgebras \cite{Frappat/Sciarrino/Sorba:1989}. #2}{3.5cm}{6.5cm}
\IfValueT{#1}{
& & \texttt{\textbackslash{}tikzset\{/Dynkin diagram,root radius=#1\}} \\
@@ -667,8 +709,8 @@ For such rare situations, there is an option:
\begingroup
-\RenewDocumentCommand\wdtA{}{.35cm}
-\RenewDocumentCommand\wdtE{}{6.55cm}
+\renewcommand{\wdtA}{.35cm}
+\renewcommand{\wdtE}{6.55cm}
\begin{dynkinTable}{Springer's table of indices \cite{Springer:2009}, pp. 320-321, with one form of \(E_7\) corrected}{2.5cm}{3.7cm}
% 1
A_n &
@@ -961,7 +1003,7 @@ We include a style called \verb!Kac! which tries to imitate the style of \cite{K
\endgroup
\section{Ceref style}
-We include a style called \verb!ceref! which shapes the root markers more oblongly and with shadows.
+We include a style called \verb!ceref! which paints oblong root markers with shadows.
The word ``ceref'' is an old form of the word ``serif''.
\begin{tcblisting}{title={Ceref style}}
\dynkin[ceref]{F}{4}
@@ -1045,9 +1087,9 @@ We have to be careful about the 4-ply foldings of \(D^{(1)}_{2\ell}\), for which
\end{dynkinDiagram}
\end{tcblisting}
\begingroup
-\RenewDocumentCommand\wdtA{}{.7cm}
-\RenewDocumentCommand\wdtD{}{3.5cm}
-\RenewDocumentCommand\wdtL{}{7cm}
+\renewcommand{\wdtA}{.7cm}
+\renewcommand{\wdtD}{3.5cm}
+\renewcommand{\wdtL}{7cm}
\NewDocumentCommand\seriesName{mmm}%
{%
\IfStrEq{#2}{0}{#1_{#3}}{#1^{#2}_{#3}}%
@@ -1152,7 +1194,7 @@ We have to be careful about the 4-ply foldings of \(D^{(1)}_{2\ell}\), for which
\end{longtable}
\endgroup
\begingroup
-\RenewDocumentCommand\wdtA{}{.8cm}
+\renewcommand{\wdtA}{.8cm}
\begin{dynkinTable}{Frobenius fixed point subgroups of finite simple groups of Lie type \cite{Carter:1995} p. 15}{3cm}{6cm}
A_{\ell\ge 1} & \dynk{A}{}
{}^2\!A_{\ell\ge 2} & \dynk[fold]{A}{}
@@ -1193,8 +1235,8 @@ Sources are Adams \cite{Adams:1996} p. 56--57, Bourbaki \cite{Bourbaki:2002} p.
\dynkin[label,ordering=Kac]{#1}{#2}\\
}%
\begin{center}
-\RenewDocumentCommand\wdtA{}{.7cm}
-\RenewDocumentCommand\wdtL{}{2.2cm}
+\renewcommand{\wdtA}{.7cm}
+\renewcommand{\wdtL}{2.2cm}
\begin{longtable}{@{}ALLLLL@{}}
\toprule
& Adams & Bourbaki & Carter & Dynkin & Kac \\ \midrule
@@ -1328,7 +1370,7 @@ Below we draw the Vogan diagrams of some affine Lie superalgebras \cite{Ransingh
\begingroup
\tikzset{/Dynkin diagram,label macro/.code=\labls{#1},label,root radius=.06cm}
\tcbset{text width=10cm}
-\RenewDocumentCommand\wdtA{}{2cm}
+\renewcommand{\wdtA}{2cm}
\NewDocumentEnvironment{Category}{m}%
{%
\begin{tcolorbox}[title={\(#1\)},breakable]{}
@@ -1673,7 +1715,7 @@ The environment syntax is \verb!\begin{dynkinDiagram}! followed by the same para
is computed as \(n=\sum 2^{i-1} a_i\), \(a_i=0\) or \(1\), to say that root \(i\) is crossed, i.e. a noncompact root. \\
\optionLabel{root radius}{\typ{number}cm}{.05cm}
& size of the dots and of the crosses in the Dynkin diagram \\
-\optionLabel{text/.style}{\typ{TikZ style data}}{scale=.7}
+\optionLabel{text style}{\typ{TikZ style data}}{scale=.7}
& Style for any labels on the roots. \\
\optionLabel{mark}{\typ{o,O,t,x,X,*}}{*}
& default root mark \\
@@ -1685,6 +1727,10 @@ is computed as \(n=\sum 2^{i-1} a_i\), \(a_i=0\) or \(1\), to say that root \(i\
& the current labelling scheme for roots. \\
\optionLabel{label macro*}{\typ{1-parameter \TeX{} macro}}{\texttt{\#1}}
& the current labelling scheme for alternate roots. \\
+\optionLabel{label height}{\typ{1-parameter \TeX{} macro}}{b}
+& the current maximal height of text labels for the roots, set by giving mathematics text of that height. \\
+\optionLabel{label depth}{\typ{1-parameter \TeX{} macro}}{g}
+& the current maximal depth of text labels for the roots, set by giving mathematics text of that depth. \\
\optionLabel{make indefinite edge}{\typ{edge pair \(i\)-\(j\) or list of such}}{\{\}}
& edge pair or list of edge pairs to treat as having indefinitely many roots on them. \\
\optionLabel{indefinite edge ratio}{\typ{float}}{1.6}
diff --git a/graphics/pgf/contrib/dynkin-diagrams/hermitian-symmetric-spaces.tex b/graphics/pgf/contrib/dynkin-diagrams/hermitian-symmetric-spaces.tex
new file mode 100644
index 0000000000..4f688c7935
--- /dev/null
+++ b/graphics/pgf/contrib/dynkin-diagrams/hermitian-symmetric-spaces.tex
@@ -0,0 +1,19 @@
+\NewDocumentCommand\HSS{mommm}
+{#1&\IfNoValueTF{#2}{\dynkin{#3}{#4}}{\dynkin[parabolic=#2]{#3}{#4}}&#5\\}
+\renewcommand*{\arraystretch}{1.5}
+\begin{longtable}
+{>{\columncolor[gray]{.9}}>$l<$>{\columncolor[gray]{.9}}>$l<$>{\columncolor[gray]{.9}}l}
+\caption{The Hermitian symmetric spaces}\endfirsthead
+\caption{\dots continued}\\ \endhead
+\caption{continued \dots}\\ \endfoot
+\endlastfoot
+\HSS{A_n}{A}{**.*x*.**}{Grassmannian of $k$-planes in $\C{n+1}$}
+\HSS{B_n}[1]{B}{}{$(2n-1)$-dimensional hyperquadric, i.e. the variety of null lines in $\C{2n+1}$}
+\HSS{C_n}[16]{C}{}{space of Lagrangian $n$-planes in $\C{2n}$}
+\HSS{D_n}[1]{D}{}{$(2n-2)$-dimensional hyperquadric, i.e. the variety of null lines in $\C{2n}$}
+\HSS{D_n}[32]{D}{}{one component of the variety of maximal dimension null subspaces of $\C{2n}$}
+\HSS{D_n}[16]{D}{}{the other component}
+\HSS{E_6}[1]{E}{6}{complexified octave projective plane}
+\HSS{E_6}[32]{E}{6}{its dual plane}
+\HSS{E_7}[64]{E}{7}{the space of null octave 3-planes in octave 6-space}
+\end{longtable}
diff --git a/graphics/pgf/contrib/dynkin-diagrams/simple-lie-algebras.tex b/graphics/pgf/contrib/dynkin-diagrams/simple-lie-algebras.tex
new file mode 100644
index 0000000000..f1dce2e3c3
--- /dev/null
+++ b/graphics/pgf/contrib/dynkin-diagrams/simple-lie-algebras.tex
@@ -0,0 +1,35 @@
+\NewDocumentEnvironment{bunch}{}%
+{\renewcommand*{\arraystretch}{1}\begin{array}{@{}ll@{}}\\ \midrule}{\\ \midrule\end{array}}
+\small
+\NewDocumentCommand\nct{mm}{\newcolumntype{#1}{>{\columncolor[gray]{.9}}>{$}m{#2cm}<{$}}}
+\nct{G}{.3}\nct{D}{2.1}\nct{W}{3}\nct{R}{3.7}\nct{S}{3}
+\NewDocumentCommand\LieG{}{\mathfrak{g}}
+\NewDocumentCommand\W{om}{\ensuremath{\mathbb{Z}^{#2}\IfValueT{#1}{/\left<#1\right>}}}
+\renewcommand*{\arraystretch}{1.5}
+\NewDocumentCommand\quo{}{\text{quotient of } E_8}
+\begin{longtable}{@{}GDWRS@{}}
+\LieG&\text{Diagram}&\text{Weights}&\text{Roots}&\text{Simple roots}\\ \midrule\endfirsthead
+\LieG&\text{Diagram}&\text{Weights}&\text{Roots}&\text{Simple roots}\\ \midrule\endhead
+A_n&\dynkin{A}{}&\frac{1}{r+1}\W[\sum e_j]{n+1}&e_i-e_j&e_i-e_{i+1}\\
+B_n&\dynkin{B}{}&\frac{1}{2}\W{n}& \pm e_i, \pm e_i \pm e_j, i\ne j&e_i-e_{i+1}, e_n\\
+C_n&\dynkin{C}{}&\W{n}& \pm 2 e_i, \pm e_i \pm e_j, i\ne j&e_i-e_{i+1}, 2e_n\\
+D_n&\dynkin{D}{}&\frac{1}{2}\W{n}& \pm e_i \pm e_j, i\ne j &
+\begin{bunch}e_i-e_{i+1},&i\le n-1\\e_{n-1}+e_n\end{bunch}\\
+E_8&\dynkin{E}{8}&\frac{1}{2}\W{8}&
+\begin{bunch}\pm2e_i\pm2e_j,&i\ne j,\\ \sum_i(-1)^{m_i}e_i,&\sum m_i \text{ even}\end{bunch}&
+\begin{bunch}
+2e_1-2e_2,\\2e_2-2e_3,\\2e_3-2e_4,\\2e_4-2e_5,\\2e_5-2e_6,\\2e_6+2e_7,\\
+-\sum e_j,\\2e_6-2e_7
+\end{bunch}\\
+E_7&\dynkin{E}{7}&\frac{1}{2}\W[e_1-e_2]{8}&\quo&\quo\\
+E_6&\dynkin{E}{6}&\frac{1}{3}\W[e_1-e_2,e_2-e_3]{8}&\quo&\quo\\
+F_4& \dynkin{F}{4}&\W{4}&
+\begin{bunch}\pm 2e_i,\\ \pm 2e_i \pm 2e_j, \quad i \ne j,\\ \pm e_1 \pm e_2 \pm e_3 \pm e_4
+\end{bunch}&
+\begin{bunch}2e_2-2e_3,\\2e_3-2e_4,\\2e_4,\\e_1-e_2-e_3-e_4\end{bunch}\\
+G_2&\dynkin{G}{2}&\W[\sum e_j]{3}&
+\begin{bunch}
+\pm(1,-1,0),\\ \pm(-1,0,1),\\ \pm(0,-1,1),\\ \pm(2,-1,-1),\\ \pm(1,-2,1),\\ \pm(-1,-1,2)
+\end{bunch}&
+\begin{bunch}(-1,0,1),\\(2,-1,-1)\end{bunch}
+\end{longtable}