42 import java.applet.Applet;
43 import java.awt.Image;
44 import java.awt.Graphics;
45 import java.awt.Dimension;
46 import java.awt.event.MouseEvent;
47 import java.awt.event.MouseListener;
48 import java.awt.event.MouseMotionListener;
50 import java.awt.image.IndexColorModel;
51 import java.awt.image.MemoryImageSource;
52 import java.io.BufferedReader;
53 import java.io.IOException;
54 import java.io.InputStream;
55 import java.io.InputStreamReader;
56 import java.io.StreamTokenizer;
57 import java.util.HashMap;
59 import java.util.logging.Level;
60 import java.util.logging.Logger;
68 final class XYZChemModel {
75 static final Map<String, Atom> atomTable =
new HashMap<String, Atom>();
76 static Atom defaultAtom;
79 atomTable.put(
"c",
new Atom(0, 0, 0));
80 atomTable.put(
"h",
new Atom(210, 210, 210));
81 atomTable.put(
"n",
new Atom(0, 0, 255));
82 atomTable.put(
"o",
new Atom(255, 0, 0));
83 atomTable.put(
"p",
new Atom(255, 0, 255));
84 atomTable.put(
"s",
new Atom(255, 255, 0));
85 atomTable.put(
"hn",
new Atom(150, 255, 150));
86 defaultAtom =
new Atom(255, 100, 200);
90 float xmin, xmax, ymin, ymax, zmin, zmax;
99 XYZChemModel(InputStream is)
throws Exception {
101 StreamTokenizer st =
new StreamTokenizer(
102 new BufferedReader(
new InputStreamReader(is,
"UTF-8")));
103 st.eolIsSignificant(
true);
109 switch (st.nextToken()) {
110 case StreamTokenizer.TT_EOF:
114 case StreamTokenizer.TT_WORD:
115 String name = st.sval;
119 if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
121 if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
123 if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
128 addVert(name, (
float) x, (
float) y, (
float) z);
129 while (st.ttype != StreamTokenizer.TT_EOL
130 && st.ttype != StreamTokenizer.TT_EOF) {
141 catch (IOException e) {
144 if (st.ttype != StreamTokenizer.TT_EOF) {
145 throw new Exception(st.toString());
151 int addVert(String name,
float x,
float y,
float z) {
156 vert =
new float[maxvert * 3];
157 atoms =
new Atom[maxvert];
160 float nv[] =
new float[maxvert * 3];
161 System.arraycopy(vert, 0, nv, 0, vert.length);
163 Atom na[] =
new Atom[maxvert];
164 System.arraycopy(atoms, 0, na, 0, atoms.length);
168 Atom a = atomTable.get(name.toLowerCase());
182 if (transformed || nvert <= 0) {
185 if (tvert ==
null || tvert.length < nvert * 3) {
186 tvert =
new int[nvert * 3];
188 mat.transform(vert, tvert, nvert);
196 void paint(Graphics g) {
197 if (vert ==
null || nvert <= 0) {
204 ZsortMap = zs =
new int[nvert];
205 for (
int i = nvert; --i >= 0;) {
217 for (
int i = nvert - 1; --i >= 0;) {
218 boolean flipped =
false;
219 for (
int j = 0; j <= i; j++) {
222 if (v[a + 2] > v[b + 2]) {
234 if (lim <= 0 || nvert <= 0) {
237 for (
int i = 0; i < lim; i++) {
247 atoms[j / 3].paint(g, v[j], v[j + 1], grey);
259 float _xmin = v[0], _xmax = _xmin;
260 float _ymin = v[1], _ymax = _ymin;
261 float _zmin = v[2], _zmax = _zmin;
262 for (
int i = nvert * 3; (i -= 3) > 0;) {
296 @SuppressWarnings(
"serial")
297 public class
XYZApp extends Applet implements Runnable, MouseListener,
298 MouseMotionListener {
301 boolean painted =
true;
304 float scalefudge = 1;
305 Matrix3D amat =
new Matrix3D(), tmat =
new Matrix3D();
306 String mdname =
null;
307 String message =
null;
313 backBuffer = createImage(getSize().width, getSize().height);
314 if (backGC !=
null) {
317 backGC = backBuffer.getGraphics();
318 backSize = getSize();
323 mdname = getParameter(
"model");
325 scalefudge = Float.valueOf(getParameter(
"scale")).floatValue();
326 }
catch (Exception ignored) {
330 if (mdname ==
null) {
331 mdname =
"model.obj";
333 resize(getSize().width <= 20 ? 400 : getSize().width,
334 getSize().height <= 20 ? 400 : getSize().height);
336 addMouseListener(
this);
337 addMouseMotionListener(
this);
342 removeMouseListener(
this);
343 removeMouseMotionListener(
this);
348 InputStream is =
null;
350 Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
351 is = getClass().getResourceAsStream(mdname);
352 XYZChemModel m =
new XYZChemModel(is);
353 Atom.setApplet(
this);
356 float xw = m.xmax - m.xmin;
357 float yw = m.ymax - m.ymin;
358 float zw = m.zmax - m.zmin;
365 float f1 = getSize().width / xw;
366 float f2 = getSize().height / xw;
367 xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge;
368 }
catch (Exception e) {
369 Logger.getLogger(
XYZApp.class.getName()).log(Level.SEVERE,
null, e);
371 message = e.toString();
377 }
catch (Exception ignored) {
384 if (md ==
null && message ==
null) {
385 new Thread(
this).start();
422 float xtheta = (prevy - y) * (360.0f / getSize().width);
423 float ytheta = (x - prevx) * (360.0f / getSize().height);
442 if (backBuffer ==
null) {
443 g.clearRect(0, 0, getSize().width, getSize().height);
452 md.mat.translate(-(md.xmin + md.xmax) / 2,
453 -(md.ymin + md.ymax) / 2,
454 -(md.zmin + md.zmax) / 2);
457 md.mat.scale(xfac, -xfac, 16 * xfac / getSize().width);
458 md.mat.translate(getSize().width / 2, getSize().height / 2, 8);
459 md.transformed =
false;
460 if (backBuffer !=
null) {
461 if (!backSize.equals(getSize())) {
464 backGC.setColor(getBackground());
465 backGC.fillRect(0, 0, getSize().width, getSize().height);
467 g.drawImage(backBuffer, 0, 0,
this);
472 }
else if (message !=
null) {
473 g.drawString(
"Error in model:", 3, 20);
474 g.drawString(message, 10, 40);
485 return "Title: XYZApp \nAuthor: James Gosling \nAn applet to put"
486 +
" a Chemical model into a page.";
492 {
"model",
"path string",
"The path to the model to be displayed"
494 +
"(see http://chem.leeds.ac.uk/Project/MIME.html)."
495 +
" Default is model.obj." },
496 {
"scale",
"float",
"Scale factor. Default is 1 (i.e. no scale)." }
505 private static Applet applet;
506 private static byte[] data;
507 private final static int R = 40;
508 private final static int hx = 15;
509 private final static int hy = 15;
510 private final static int bgGrey = 192;
511 private final static int nBalls = 16;
512 private static int maxr;
516 private Image balls[];
519 data =
new byte[R * 2 * R * 2];
521 for (
int Y = 2 * R; --Y >= 0;) {
522 int x0 = (int) (Math.sqrt(R * R - (Y - R) * (Y - R)) + 0.5);
523 int p = Y * (R * 2) + R - x0;
524 for (
int X = -x0; X < x0; X++) {
527 int r = (int) (Math.sqrt(x * x + y * y) + 0.5);
531 data[p++] = r <= 0 ? 1 : (byte) r;
537 static void setApplet(Applet app) {
541 Atom(
int Rl,
int Gl,
int Bl) {
547 private int blend(
int fg,
int bg,
float fgfactor) {
548 return (
int) (bg + (fg - bg) * fgfactor);
551 private void Setup() {
552 balls =
new Image[nBalls];
553 byte red[] =
new byte[256];
554 red[0] = (byte) bgGrey;
555 byte green[] =
new byte[256];
556 green[0] = (byte) bgGrey;
557 byte blue[] =
new byte[256];
558 blue[0] = (byte) bgGrey;
559 for (
int r = 0; r < nBalls; r++) {
560 float b = (float) (r + 1) / nBalls;
561 for (
int i = maxr; i >= 1; --i) {
562 float d = (float) i / maxr;
563 red[i] = (byte) blend(blend(Rl, 255, d), bgGrey, b);
564 green[i] = (byte) blend(blend(Gl, 255, d), bgGrey, b);
565 blue[i] = (byte) blend(blend(Bl, 255, d), bgGrey, b);
567 IndexColorModel model =
new IndexColorModel(8, maxr + 1,
568 red, green, blue, 0);
569 balls[r] = applet.createImage(
570 new MemoryImageSource(R * 2, R * 2, model, data, 0, R * 2));
574 void paint(Graphics gc,
int x,
int y,
int r) {
582 gc.drawImage(i, x - (size >> 1), y - (size >> 1), size, size, applet);