# To unbundle, sh this file echo README 1>&2 sed 's/.//' >README <<'//GO.SYSIN DD README' -INSTALLATION - -The file chem invokes chem.awk, which is where the dirty -work gets done. chem.awk tells pic to include a copy -of chem.macros; you will need to change a pathname on -the 2nd line of chem.awk. - -You need current versions of awk and pic. In particular, -your awk has to support functions and your pic has to know -about the copy statement. So if you get weird messages -from either of those, it's time to update. - -this version of awk is available from the AT&T Toolchest, -for a fee of $300. For more -information, call 201-522-6900 and log in as "guest". -The current version of pic is part of the documentor's -workbench version 2.0, or the typesetter-independent -troff package; both of these are available from AT&T -Software Sales at POBox 25000, Greensboro, NC 27420, 800-828-unix. -You don't want to know why there are different places and -different sources. - -There are several test files called *.p. - - -INTRODUCTION - -"chem" is yet another preprocessor like eqn, pic, etc., -this time for producing chemical structure diagrams. -Today's version is best suited for organic chemistry -(bonds, rings) and it's excruciatingly slow sometimes. -Who knows what the future may hold. - -In a style reminiscent of eqn and pic, diagrams are -written in a special language and occur in a document -surrounded by lines beginning - .cstart -and - .cend -(in the first column, naturally). Anything outside -these is copied through intact; whatever is between -.cstart and .cend is converted into pic commands to -draw the diagram. - -So as a bare minimum, - - .cstart - CH3 - bond - CH3 - .cend - -prints two CH3 groups with a bond between them. -To actually print this, you must run chem, pic, -troff, and your output filter on whatever file -contains the input: - - chem [file...] | pic | troff ... | ... - -(By the way, chem needs the current version of awk; -you will get some mysterious error messages from awk -if your version is too old. You will also profit from -having sensible and consistent definitions for the PS -and PE macros.) - - -THE LANGUAGE - -The chem input language is rather small. It provides -bonds of several styles, moieties (e.g., C, NH3, ...), -rings of several styles, and a way to glue them together -as desired. In addition, since chem is a pic preprocessor, -it's possible to include pic statements in the middle of -a diagram to draw things not provided for by chem itself. - -Bonds: - - bond [direction] [length n] [from Name | picstuff] - -draws a single bond in direction from nearest corner of Name -"bond" can also be double bond, front bond, back bond, etc. -(We'll get back to "Name" in a minute.) - -"direction" is the angle in degrees (0 up, positive clockwise) -or a direction word like up, down, sw (= southwest), etc. -If no direction is specified, the bond goes in the current -direction (usually that of the last bond). - -Normally the bond begins at the last object placed; this -can be changed by naming a "from" place. For instance, -to make a simple alkyl chain: - - CH3 - bond (this one goes right from the CH3) - C (at the right end of the bond) - double bond up (from the C) - O (at the end of the double bond) - bond right from C - CH3 - -A length in inches may be specified to override the default length. -Other pic commands can be tacked on to the end of a bond command, -to created dotted or dashed bonds or to specify a "to" place. - - -Names: - -In the alkyl chain above, notice that the carbon atom C -was used both to draw something and as the name for a place. -A moiety always defines a name for a place; you can use -your own names for places instead, and indeed, for rings -you will have to. A name is just - - Name: ... - -"Name" is often the name of a moiety like CH3, but it -needn't be. Any name that begins with a capital letter -and contains only letters and numbers is ok: - - First: bond - bond 30 from First - -draws something like - - / - ____/ - - -Moieties: - -A moiety is a string of characters beginning with a capital letter, -such as N(C2H5)2. Numbers are converted to subscripts (unless -they appear to be fractional values, as in N2.5H). The moiety -names itself after special characters have been stripped out: -N(C2H5)2) has the name NC2H52. - -BP is a special "branch point" (i.e., line crossing) that doesn't print. - -Normally a moiety is placed right after the last thing mentioned, -but it may be positioned by pic-like commands, e.g., - - CH3 at C + (0.5,0.5) - -Text within quotes "..." is treated more or less like a -moiety except that no changes are made to the quoted part. - - -Rings: - -There are lots of rings, but only 5 and 6-sided rings get -much support. "ring" by itself is a 6-sided ring; -"benzene" is the benzene ring with a circle inside. -"aromatic" puts a circle into any kind of ring. - - ring [pointing up|right|left|down] [aromatic] - [put Mol at n] [double i,j k,l ...] - [picstuff] - -The vertices of a ring are numbered 1,2,... from the vertex -that points in the natural compass direction. So for a -hexagonal ring with the point at the top, the top vertex is 1, -while if the ring has a point at the east side, that is -vertex 1. This is expressed as - - R1: ring pointing up - R2: ring pointing right - -The ring vertices are named .V1 .. .Vn, with .V1 in the -pointing direction. So the corners of R1 are R1.V1 (the "top"), -R1.V2, R1.V3, R1.V4 (the "bottom"), etc., whereas for R2, -R2.V1 is the rightmost vertex and R2.V4 the leftmost. These -vertex names are used for connecting bonds or other rings. -For example: - - R1: benzene pointing right - R2: benzene pointing right with .V6 at R1.V2 - -creates two benzene rings connected along a side. - -Interior double bonds are specified as "double n1,n2 n3,n4 ..."; -each number pair adds an interior bond. So the alternate form -of a benzene ring is - - ring double 1,2 3,4 5,6 - -Heterocycles (rings with something other than carbon at a vertex) -are written as "put X at V", as in - - R: ring put N at 1 put O at 2 - -In this heterocycle, R.N and R.O become synonyms for R.V1 and R.V2. - -There are two 5-sided rings. "ring5" is pentagonal with a side -that matches the 6-sided ring; it has four natural directions. -A "flatring" is a 5-sided ring created by chopping one corner -of a 6-sided ring so that it exactly matches the 6-sided rings. - -The description of a ring has to fit on a single line. - - -Miscellaneous: - -The specific construction - - bond... ; moiety (spaces matter!) - -is equivalent to - - bond - moiety - -Otherwise, each item has to be on a separate line (and only one line). - -A period "." in column 1 signals a troff command, which is copied -through as is. - -A line whose first non-blank character is a # is treated as a comment. - -A line whose first word is "pic" is copied through as is after -the "pic" has been removed. - -The command - - size n - -scales the diagram so it looks plausible at point size n -(default is 10 point). - -Anything else is assumed to be pic and is copied through with -a label. - -WISH LIST - -It's too slow (but it's too early in the game to optimize). - -Error checking is minimal; errors are usually detected -and reported in an oblique fashion by pic. - -There's no library or file inclusion mechanism, and there's -no shorthand for repetitive structures. - -The extension mechanism is to create pic macros, but these -are tricky to get right and don't have all the properties -of built-in objects. - -There's no in-line chemistry yet (e.g., analogous to -the $...$ construct of eqn). - -There is no way to control entry point for bonds on groups. -Normally a bond connects to the carbon atom if entering from -the top or bottom and otherwise to the nearest corner. - -Bonds from substituted atoms on heterocycles do not join -at the proper place without adding a bit of pic. - -There is no decent primitive for brackets. - -Text (quoted strings) doesn't work very well. - -A squiggle bond is needed. - - -COMPLAINTS - -If something doesn't work, or if you can see a way to -make something better, let us know. - - jon bentley - lynn jelinski - brian kernighan //GO.SYSIN DD README echo chem 1>&2 sed 's/.//' >chem <<'//GO.SYSIN DD chem' -for i in $* -do - if test ! -r $i - then - echo "chem: can't open file $i" 1>&2 - exit 1 - fi -done -awk -f chem.awk $* //GO.SYSIN DD chem echo chem.awk 1>&2 sed 's/.//' >chem.awk <<'//GO.SYSIN DD chem.awk' -BEGIN { - macros = "/usr/bwk/chem/chem.macros" # CHANGE ME!!!!! - - pi = 3.141592654 - deg = 57.29578 - setparams(1.0) - set(dc, "up 0 right 90 down 180 left 270 ne 45 se 135 sw 225 nw 315") - set(dc, "0 n 30 ne 45 ne 60 ne 90 e 120 se 135 se 150 se 180 s") - set(dc, "300 nw 315 nw 330 nw 270 w 210 sw 225 sw 240 sw") -} -function init() { - printf ".PS\n" - if (firsttime++ == 0) { - printf "copy \"%s\"\n", macros - printf "\ttextht = %g; textwid = .1; cwid = %g\n", textht, cwid - printf "\tlineht = %g; linewid = %g\n", lineht, linewid - } - printf "Last: 0,0\n" - RING = "R"; MOL = "M"; BOND = "B"; OTHER = "O" # manifests - last = OTHER - dir = 90 -} -function setparams(scale) { - lineht = scale * 0.2 - linewid = scale * 0.2 - textht = scale * 0.16 - db = scale * 0.2 # bond length - cwid = scale * 0.12 # character width - cr = scale * 0.08 # rad of invis circles at ring vertices - crh = scale * 0.16 # ht of invis ellipse at ring vertices - crw = scale * 0.12 # wid - dav = scale * 0.015 # vertical shift up for atoms in atom macro - dew = scale * 0.02 # east-west shift for left of/right of - ringside = scale * 0.3 # side of all rings - dbrack = scale * 0.1 # length of bottom of bracket -} - - { lineno++ } - -/^(\.cstart)|(begin chem)/ { init(); inchem = 1; next } -/^(\.cend)|(end)/ { inchem = 0; print ".PE"; next } - -/^\./ { print; next } # troff - -inchem == 0 { print; next } # everything else - -$1 == "pic" { shiftfields(1); print; next } # pic pass-thru -$1 ~ /^#/ { next } # comment - -$1 == "textht" { textht = $NF; next } -$1 == "cwid" { cwid = $NF; next } -$1 == "db" { db = $NF; next } -$1 == "size" { if ($NF <= 4) size = $NF; else size = $NF/10 - setparams(size); next } - - { print "\n#", $0 } # debugging, etc. - { lastname = "" } - -$1 ~ /^[A-Z].*:$/ { # label; falls thru after shifting left - lastname = substr($1, 1, length($1)-1) - print $1 - shiftfields(1) -} - -$1 ~ /^\"/ { print "Last: ", $0; last = OTHER; next } - -$1 ~ /bond/ { bond($1); next } -$1 ~ /^(double|triple|front|back)$/ && $2 == "bond" { - $1 = $1 $2; shiftfields(2); bond($1); next } - -$1 == "aromatic" { temp = $1; $1 = $2; $2 = temp } -$1 ~ /ring|benz/ { ring($1); next } - -$1 == "methyl" { $1 = "CH3" } # left here as an example - -$1 ~ /^[A-Z]/ { molecule(); next } - -$1 == "left" { left[++stack] = fields(2, NF); printf("Last: [\n"); next } - -$1 == "right" { bracket(); stack--; next } - -$1 == "label" { label(); next } - -/./ { print "Last: ", $0; last = OTHER } - -END { if (firsttime == 0) error("did you forget .cstart and .cend?") - if (inchem) printf ".PE\n" -} - -function bond(type, i, goes, from) { - goes = "" - for (i = 2; i <= NF; i++) - if ($i == ";") { - goes = $(i+1) - NF = i - 1 - break - } - leng = db - from = "" - for (cf = 2; cf <= NF; ) { - if ($cf ~ /(\+|-)?[0-9]+|up|down|right|left|ne|se|nw|sw/) - dir = cvtdir(dir) - else if ($cf ~ /^leng/) { - leng = $(cf+1) - cf += 2 - } else if ($cf == "to") { - leng = 0 - from = fields(cf, NF) - break - } else if ($cf == "from") { - from = dofrom() - break - } else if ($cf ~ /^#/) { - cf = NF+1 - break; - } else { - from = fields(cf, NF) - break - } - } - if (from ~ /( to )|^to/) # said "from ... to ...", so zap length - leng = 0 - else if (from == "") # no from given at all - from = "from Last." leave(last, dir) " " fields(cf, NF) - printf "Last: %s(%g, %g, %s)\n", type, leng, dir, from - last = BOND - if (lastname != "") - labsave(lastname, last, dir) - if (goes) { - $0 = goes - molecule() - } -} - -function dofrom( n, s) { - cf++ # skip "from" - n = $cf - if (n in labtype) # "from Thing" => "from Thing.V.s" - return "from " n "." leave(labtype[n], dir) - if (n ~ /^\.[A-Z]/) # "from .V" => "from Last.V.s" - return "from Last" n "." corner(dir) - if (n ~ /^[A-Z][^.]*\.[A-Z][^.]*$/) # "from X.V" => "from X.V.s" - return "from " n "." corner(dir) - return fields(cf-1, NF) -} - -function bracket( t) { - printf("]\n") - if ($2 == ")") - t = "spline" - else - t = "line" - printf("%s from last [].sw+(%g,0) to last [].sw to last [].nw to last [].nw+(%g,0)\n", - t, dbrack, dbrack) - printf("%s from last [].se-(%g,0) to last [].se to last [].ne to last [].ne-(%g,0)\n", - t, dbrack, dbrack) - if ($3 == "sub") - printf("\" %s\" ljust at last [].se\n", fields(4,NF)) -} - -function molecule( n, type) { - n = $1 - if (n == "BP") { - $1 = "\"\" ht 0 wid 0" - type = OTHER - } else { - $1 = atom(n) - type = MOL - } - gsub(/[^A-Za-z0-9]/, "", n) # for stuff like C(OH3): zap non-alnum - if ($2 == "") - printf "Last: %s: %s with .%s at Last.%s\n", \ - n, $0, leave(type,dir+180), leave(last,dir) - else if ($2 == "below") - printf("Last: %s: %s with .n at %s.s\n", n, $1, $3) - else if ($2 == "above") - printf("Last: %s: %s with .s at %s.n\n", n, $1, $3) - else if ($2 == "left" && $3 == "of") - printf("Last: %s: %s with .e at %s.w+(%g,0)\n", n, $1, $4, dew) - else if ($2 == "right" && $3 == "of") - printf("Last: %s: %s with .w at %s.e-(%g,0)\n", n, $1, $4, dew) - else - printf "Last: %s: %s\n", n, $0 - last = type - if (lastname != "") - labsave(lastname, last, dir) - labsave(n, last, dir) -} - -function label( i, v) { - if (substr(labtype[$2], 1, 1) != RING) - error(sprintf("%s is not a ring", $2)) - else { - v = substr(labtype[$2], 2, 1) - for (i = 1; i <= v; i++) - printf("\"\\s-3%d\\s0\" at 0.%d<%s.C,%s.V%d>\n", i, v+2, $2, $2, i) - } -} - -function ring(type, typeint, pt, verts, i) { - pt = 0 # points up by default - if (type ~ /[1-8]$/) - verts = substr(type, length(type), 1) - else if (type ~ /flat/) - verts = 5 - else - verts = 6 - fused = other = "" - for (i = 1; i <= verts; i++) - put[i] = dbl[i] = "" - nput = aromatic = withat = 0 - for (cf = 2; cf <= NF; ) { - if ($cf == "pointing") - pt = cvtdir(0) - else if ($cf == "double" || $cf == "triple") - dblring(verts) - else if ($cf ~ /arom/) { - aromatic++ - cf++ # handled later - } else if ($cf == "put") { - putring(verts) - nput++ - } else if ($cf ~ /^#/) { - cf = NF+1 - break; - } else { - if ($cf == "with" || $cf == "at") - withat = 1 - other = other " " $cf - cf++ - } - } - typeint = RING verts pt # RING | verts | dir - if (withat == 0) - fused = joinring(typeint, dir, last) - printf "Last: [\n" - makering(type, pt, verts) - printf "] %s %s\n", fused, other - last = typeint - if (lastname != "") - labsave(lastname, last, dir) -} - -function makering(type, pt, v, i, a, r) { - if (type ~ /flat/) - v = 6 - # vertices - r = ringside / (2 * sin(pi/v)) - printf "\tC: 0,0\n" - for (i = 0; i <= v+1; i++) { - a = ((i-1) / v * 360 + pt) / deg - printf "\tV%d: (%g,%g)\n", i, r * sin(a), r * cos(a) - } - if (type ~ /flat/) { - printf "\tV4: V5; V5: V6\n" - v = 5 - } - # sides - if (nput > 0) { # hetero ... - for (i = 1; i <= v; i++) { - c1 = c2 = 0 - if (put[i] != "") { - printf("\tV%d: ellipse invis ht %g wid %g at V%d\n", - i, crh, crw, i) - printf("\t%s at V%d\n", put[i], i) - c1 = cr - } - j = i+1 - if (j > v) - j = 1 - if (put[j] != "") - c2 = cr - printf "\tline from V%d to V%d chop %g chop %g\n", i, j, c1, c2 - if (dbl[i] != "") { # should check i to %g chop %g chop %g\n", - rat, i, rat, j, c1, c2 - if (dbl[i] == "triple") - printf "\tline from %g to %g chop %g chop %g\n", - 2-rat, i, 2-rat, j, c1, c2 - } - } - } else { # regular - for (i = 1; i <= v; i++) { - j = i+1 - if (j > v) - j = 1 - printf "\tline from V%d to V%d\n", i, j - if (dbl[i] != "") { # should check i to %g\n", - rat, i, rat, j - if (dbl[i] == "triple") - printf "\tline from %g to %g\n", - 2-rat, i, 2-rat, j - } - } - } - # punt on triple temporarily - # circle - if (type ~ /benz/ || aromatic > 0) { - if (type ~ /flat/) - r *= .4 - else - r *= .5 - printf "\tcircle rad %g at 0,0\n", r - } -} - -function putring(v) { # collect "put Mol at n" - cf++ - mol = $(cf++) - if ($cf == "at") - cf++ - if ($cf >= 1 && $cf <= v) { - m = mol - gsub(/[^A-Za-z0-9]/, "", m) - put[$cf] = m ":" atom(mol) - } - cf++ -} - -function joinring(type, dir, last) { # join a ring to something - if (substr(last, 1, 1) == RING) { # ring to ring - if (substr(type, 3) == substr(last, 3)) # fails if not 6-sided - return "with .V6 at Last.V2" - } - # if all else fails - return sprintf("with .%s at Last.%s", \ - leave(type,dir+180), leave(last,dir)) -} - -function leave(last, d, c, c1) { # return vertex of last in dir d - if (last == BOND) - return "end" - d = reduce(d) - if (substr(last, 1, 1) == RING) - return ringleave(last, d) - if (last == MOL) { - if (d == 0 || d == 180) - c = "C" - else if (d > 0 && d < 180) - c = "R" - else - c = "L" - if (d in dc) - c1 = dc[d] - else - c1 = corner(d) - return sprintf("%s.%s", c, c1) - } - if (last == OTHER) - return corner(d) - return "c" -} - -function ringleave(last, d, rd, verts) { # return vertex of ring in dir d - verts = substr(last, 2, 1) - rd = substr(last, 3) - return sprintf("V%d.%s", int(reduce(d-rd)/(360/verts)) + 1, corner(d)) -} - -function corner(dir) { - return dc[reduce(45 * int((dir+22.5)/45))] -} - -function labsave(name, type, dir) { - labtype[name] = type - labdir[name] = dir -} - -function dblring(v, d, v1, v2) { # should canonicalize to i,i+1 mod v - d = $cf - for (cf++; $cf ~ /^[1-9]/; cf++) { - v1 = substr($cf,1,1) - v2 = substr($cf,3,1) - if (v2 == v1+1 || v1 == v && v2 == 1) # e.g., 2,3 or 5,1 - dbl[v1] = d - else if (v1 == v2+1 || v2 == v && v1 == 1) # e.g., 3,2 or 1,5 - dbl[v2] = d - else - error(sprintf("weird %s bond in\n\t%s", d, $0)) - } -} - -function cvtdir(d) { # maps "[pointing] somewhere" to degrees - if ($cf == "pointing") - cf++ - if ($cf ~ /^[+\-]?[0-9]+/) - return reduce($(cf++)) - else if ($cf ~ /left|right|up|down|ne|nw|se|sw/) - return reduce(dc[$(cf++)]) - else { - cf++ - return d - } -} - -function reduce(d) { # reduces d to 0 <= d < 360 - while (d >= 360) - d -= 360 - while (d < 0) - d += 360 - return d -} - -function atom(s, c, i, n, nsub, cloc, nsubc) { # convert CH3 to atom(...) - if (s == "\"\"") - return s - n = length(s) - nsub = nsubc = 0 - cloc = index(s, "C") - if (cloc == 0) - cloc = 1 - for (i = 1; i <= n; i++) - if (substr(s, i, 1) !~ /[A-Z]/) { - nsub++ - if (i < cloc) - nsubc++ - } - gsub(/([0-9]+\.[0-9]+)|([0-9]+)/, "\\s-3\\d&\\u\\s+3", s) - if (s ~ /([^0-9]\.)|(\.[^0-9])/) # centered dot - gsub(/\./, "\\v#-.3m#.\\v#.3m#", s) - return sprintf("atom(\"%s\", %g, %g, %g, %g, %g, %g)", - s, (n-nsub/2)*cwid, textht, (cloc-nsubc/2-0.5)*cwid, crh, crw, dav) -} - -function inline( i, n, s, s1, os) { - s = $0 - os = "" - while ((n = match(s, /!?[A-Z][A-Za-z]*(([0-9]+\.[0-9]+)|([0-9]+))/)) > 0) { - os = os substr(s, 1, n-1) # prefix - s1 = substr(s, n, RLENGTH) # molecule - if (substr(s1, 1, 1) == "!") { # !mol => leave alone - s1 = substr(s1, 2) - } else { - gsub(/([0-9]+\.[0-9]+)|([0-9]+)/, "\\s-3\\d&\\u\\s+3", s1) - if (s1 ~ /([^0-9]\.)|(\.[^0-9])/) # centered dot - gsub(/\./, "\\v#-.3m#.\\v#.3m#", s1) - } - os = os s1 - s = substr(s, n + RLENGTH) # tail - } - os = os s - print os - return -} - -function shiftfields(n, i) { # move $n+1..$NF to $n..$NF-1, zap $NF - for (i = n; i < NF; i++) - $i = $(i+1) - $NF = "" - NF-- -} - -function fields(n1, n2, i, s) { - if (n1 > n2) - return "" - s = "" - for (i = n1; i <= n2; i++) { - if ($i ~ /^#/) - break; - s = s $i " " - } - return s -} - -function set(a, s, i, n, q) { - n = split(s, q) - for (i = 1; i <= n; i += 2) - a[q[i]] = q[i+1] -} - -function error(s) { - printf "chem\007: error on line %d: %s\n", lineno, s | "cat 1>&2" -} //GO.SYSIN DD chem.awk echo chem.macros 1>&2 sed 's/.//' >chem.macros <<'//GO.SYSIN DD chem.macros' -# macros for chem - -pi = 3.141592654 -deg = 57.29578 -# cr = 0.08 # radius of invis circle at ring vertices (see cr[vh]) -# crh = 0.16; crw = 0.12 # ht & wid of invis ellipse around atoms at ring vertices -# dav = 0.015 # vertical shift up for atoms in atom macro - -# atom(text, wid, ht, carbon position, crh, crw, dav) -define atom { [ - T: $1 wid $2 ht $3-2*$7 - C: ellipse invis ht $5 wid $6 at T.w + ($4,$7) - L: ellipse invis ht $5 wid $6 at T.w + (cwid/2,$7) - R: ellipse invis ht $5 wid $6 at T.e + (-cwid/2,$7) -] } - -# bond(length, angle in degrees, whatever) -define bond { - line $3 by ($1) * sin(($2)/deg), ($1) * cos(($2)/deg) -} - -# fancy bonds: r, theta, from/at -define doublebond { - line $3 invis by ($1) * sin(($2)/deg), ($1) * cos(($2)/deg) - V1: last line.start; V2: last line.end; dx = V2.x-V1.x; dy = V2.y-V1.y - norm = sqrt(dx*dx + dy*dy) - ny = dx * .02 / norm - nx = -dy * .02 / norm - line from V1 + (nx,ny) to V2 + (nx,ny) - line from V1 - (nx,ny) to V2 - (nx,ny) - move to V2 -} -define triplebond { - line $3 invis by ($1) * sin(($2)/deg), ($1) * cos(($2)/deg) - V1: last line.start; V2: last line.end; dx = V2.x-V1.x; dy = V2.y-V1.y - norm = sqrt(dx*dx + dy*dy) - ny = dx * .025 / norm - nx = -dy * .025 / norm - line from V1 + (nx,ny) to V2 + (nx,ny) - line from V1 - (nx,ny) to V2 - (nx,ny) - line from V1 to V2 - move to V2 -} -define backbond { - line $3 invis by ($1) * sin(($2)/deg), ($1) * cos(($2)/deg) - V1: last line.start; V2: last line.end; dx = V2.x-V1.x; dy = V2.y-V1.y - norm = sqrt(dx*dx + dy*dy) - n = norm / .025 - ny = dx * .02 / norm - nx = -dy * .02 / norm - for i = 1 to n-1 do { - XZ: i/n - line from XZ + (nx,ny) to XZ - (nx,ny) - } - move to V2 -} -define frontbond { - line $3 invis by ($1) * sin(($2)/deg), ($1) * cos(($2)/deg) - V1: last line.start; V2: last line.end; dx = V2.x-V1.x; dy = V2.y-V1.y - ah = arrowht; aw = arrowwid; ahead = arrowhead - arrowht = sqrt(dx*dx + dy*dy) - arrowwid = 0.05 - arrowhead = 7 - line <- from V1 to V2 - arrowht = ah; arrowwid = aw; arrowhead = ahead -} //GO.SYSIN DD chem.macros echo PS-PEmacros 1>&2 sed 's/.//' >PS-PEmacros <<'//GO.SYSIN DD PS-PEmacros' -.de PS \" start picture -. \" $1 is height, $2 is width, both in inches -.if \\$1>0 .sp .35 -.in (\\n(.lu-\\$2)/2u -.ne \\$1 -.. -.de PE \" end of picture -.in -.if \\$1>0 .sp .65 -.. //GO.SYSIN DD PS-PEmacros echo lsd.p 1>&2 sed 's/.//' >lsd.p <<'//GO.SYSIN DD lsd.p' -.cstart -# Lysergic acid dethylamide -B: benzene pointing right -F: flatring5 pointing left put N at 5 double 3,4 with .V1 at B.V2 - H below F.N -R: ring pointing right with .V4 at B.V6 - front bond right from R.V6 ; H -R: ring pointing right with .V2 at R.V6 put N at 1 double 3,4 - bond right from R.N ; CH3 - back bond -60 from R.V5 ; H - bond up from R.V5 ; CO - bond right ; N(C2H5)2 -.cend //GO.SYSIN DD lsd.p echo eth.p 1>&2 sed 's/.//' >eth.p <<'//GO.SYSIN DD eth.p' -.cstart -# Ethamivan - -R: ring pointing right double 1,2 3,4 5,6 - bond left from R ; OH - bond -150 from R ; OCH3 - bond right from R ; C - double bond up ; O - bond right from C ; N - bond 45 ; C2H5 - bond 135 from N ; C2H5 -.cend //GO.SYSIN DD eth.p echo morphine.p 1>&2 sed 's/.//' >morphine.p <<'//GO.SYSIN DD morphine.p' -.cstart -# This is a structure of morphine, for comparison with the one -# in the preprint by Broadbent and Norris -# -R1: ring6 double 1,2 - bond -60 from R1.V6 ; HO -R2: ring6 with .V1 at R1.V3 - bond 60 from R2.V2 ; N - bond right from N ; CH3 -R3: benzene with .V1 at R2.V5 - bond -120 from R3.V5 ; HO -# this is the furan ring - bond -135 length .3 from R1.V5 ; O - bond -45 length .3 from R3.V6 -# this is the odd ring - bond up length .1 from N ; BP -B1: bond up length .35 from R1.V4 - bond to BP -.cend //GO.SYSIN DD morphine.p