0N/A/*
3845N/A * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A *
0N/A * Redistribution and use in source and binary forms, with or without
0N/A * modification, are permitted provided that the following conditions
0N/A * are met:
0N/A *
0N/A * - Redistributions of source code must retain the above copyright
0N/A * notice, this list of conditions and the following disclaimer.
0N/A *
0N/A * - Redistributions in binary form must reproduce the above copyright
0N/A * notice, this list of conditions and the following disclaimer in the
0N/A * documentation and/or other materials provided with the distribution.
0N/A *
2362N/A * - Neither the name of Oracle nor the names of its
0N/A * contributors may be used to endorse or promote products derived
0N/A * from this software without specific prior written permission.
0N/A *
0N/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
0N/A * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
0N/A * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0N/A * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
0N/A * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0N/A * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0N/A * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
0N/A * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0N/A * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0N/A * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0N/A * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0N/A */
0N/A
4378N/A/*
4378N/A * This source code is provided to illustrate the usage of a given feature
4378N/A * or technique and has been deliberately simplified. Additional steps
4378N/A * required for a production-quality application, such as security checks,
4378N/A * input validation and proper error handling, might not be present in
4378N/A * this sample code.
4378N/A */
4378N/A
4378N/A
3845N/A
3845N/Aimport java.applet.Applet;
3845N/Aimport java.awt.Image;
3845N/Aimport java.awt.Graphics;
3845N/Aimport java.awt.Dimension;
3845N/Aimport java.awt.event.MouseEvent;
3845N/Aimport java.awt.event.MouseListener;
3845N/Aimport java.awt.event.MouseMotionListener;
3845N/Aimport java.net.URL;
3845N/Aimport java.awt.image.IndexColorModel;
3845N/Aimport java.awt.image.MemoryImageSource;
3845N/Aimport java.io.BufferedReader;
3845N/Aimport java.io.IOException;
3845N/Aimport java.io.InputStream;
3845N/Aimport java.io.InputStreamReader;
3845N/Aimport java.io.StreamTokenizer;
3845N/Aimport java.util.HashMap;
3845N/Aimport java.util.Map;
3845N/Aimport java.util.logging.Level;
3845N/Aimport java.util.logging.Logger;
3845N/A
0N/A
0N/A/*
0N/A * A set of classes to parse, represent and display Chemical compounds in
0N/A * .xyz format (see http://chem.leeds.ac.uk/Project/MIME.html)
0N/A */
3845N/A/** The representation of a Chemical .xyz model */
3845N/Afinal class XYZChemModel {
0N/A
0N/A float vert[];
0N/A Atom atoms[];
0N/A int tvert[];
0N/A int ZsortMap[];
0N/A int nvert, maxvert;
3845N/A static final Map<String, Atom> atomTable = new HashMap<String, Atom>();
3845N/A static Atom defaultAtom;
0N/A
0N/A static {
0N/A atomTable.put("c", new Atom(0, 0, 0));
0N/A atomTable.put("h", new Atom(210, 210, 210));
0N/A atomTable.put("n", new Atom(0, 0, 255));
0N/A atomTable.put("o", new Atom(255, 0, 0));
0N/A atomTable.put("p", new Atom(255, 0, 255));
0N/A atomTable.put("s", new Atom(255, 255, 0));
0N/A atomTable.put("hn", new Atom(150, 255, 150)); /* !!*/
0N/A defaultAtom = new Atom(255, 100, 200);
0N/A }
0N/A boolean transformed;
0N/A Matrix3D mat;
0N/A float xmin, xmax, ymin, ymax, zmin, zmax;
0N/A
3845N/A XYZChemModel() {
0N/A mat = new Matrix3D();
0N/A mat.xrot(20);
0N/A mat.yrot(30);
0N/A }
0N/A
3845N/A /** Create a Chemical model by parsing an input stream */
3845N/A XYZChemModel(InputStream is) throws Exception {
3845N/A this();
3845N/A StreamTokenizer st = new StreamTokenizer(
3845N/A new BufferedReader(new InputStreamReader(is, "UTF-8")));
3845N/A st.eolIsSignificant(true);
3845N/A st.commentChar('#');
0N/A
3845N/A try {
3845N/A scan:
3845N/A while (true) {
3845N/A switch (st.nextToken()) {
3845N/A case StreamTokenizer.TT_EOF:
3845N/A break scan;
3845N/A default:
3845N/A break;
3845N/A case StreamTokenizer.TT_WORD:
3845N/A String name = st.sval;
3845N/A double x = 0,
3845N/A y = 0,
3845N/A z = 0;
3845N/A if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
3845N/A x = st.nval;
3845N/A if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
3845N/A y = st.nval;
3845N/A if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
3845N/A z = st.nval;
3845N/A }
3845N/A }
3845N/A }
3845N/A addVert(name, (float) x, (float) y, (float) z);
3845N/A while (st.ttype != StreamTokenizer.TT_EOL
3845N/A && st.ttype != StreamTokenizer.TT_EOF) {
3845N/A st.nextToken();
3845N/A }
0N/A
3845N/A } // end Switch
0N/A
3845N/A } // end while
0N/A
3845N/A is.close();
0N/A
3845N/A } // end Try
3845N/A catch (IOException e) {
3845N/A }
0N/A
3845N/A if (st.ttype != StreamTokenizer.TT_EOF) {
3845N/A throw new Exception(st.toString());
3845N/A }
0N/A
0N/A } // end XYZChemModel()
0N/A
0N/A /** Add a vertex to this model */
0N/A int addVert(String name, float x, float y, float z) {
0N/A int i = nvert;
3845N/A if (i >= maxvert) {
0N/A if (vert == null) {
0N/A maxvert = 100;
0N/A vert = new float[maxvert * 3];
0N/A atoms = new Atom[maxvert];
0N/A } else {
0N/A maxvert *= 2;
0N/A float nv[] = new float[maxvert * 3];
0N/A System.arraycopy(vert, 0, nv, 0, vert.length);
0N/A vert = nv;
0N/A Atom na[] = new Atom[maxvert];
0N/A System.arraycopy(atoms, 0, na, 0, atoms.length);
0N/A atoms = na;
0N/A }
3845N/A }
3845N/A Atom a = atomTable.get(name.toLowerCase());
3845N/A if (a == null) {
3845N/A a = defaultAtom;
3845N/A }
0N/A atoms[i] = a;
0N/A i *= 3;
0N/A vert[i] = x;
0N/A vert[i + 1] = y;
0N/A vert[i + 2] = z;
0N/A return nvert++;
0N/A }
0N/A
0N/A /** Transform all the points in this model */
0N/A void transform() {
3845N/A if (transformed || nvert <= 0) {
0N/A return;
3845N/A }
3845N/A if (tvert == null || tvert.length < nvert * 3) {
0N/A tvert = new int[nvert * 3];
3845N/A }
0N/A mat.transform(vert, tvert, nvert);
0N/A transformed = true;
0N/A }
0N/A
0N/A /** Paint this model to a graphics context. It uses the matrix associated
3845N/A with this model to map from model space to screen space.
3845N/A The next version of the browser should have double buffering,
3845N/A which will make this *much* nicer */
0N/A void paint(Graphics g) {
3845N/A if (vert == null || nvert <= 0) {
0N/A return;
3845N/A }
0N/A transform();
0N/A int v[] = tvert;
0N/A int zs[] = ZsortMap;
0N/A if (zs == null) {
0N/A ZsortMap = zs = new int[nvert];
3845N/A for (int i = nvert; --i >= 0;) {
0N/A zs[i] = i * 3;
3845N/A }
0N/A }
0N/A
0N/A /*
0N/A * I use a bubble sort since from one iteration to the next, the sort
0N/A * order is pretty stable, so I just use what I had last time as a
0N/A * "guess" of the sorted order. With luck, this reduces O(N log N)
0N/A * to O(N)
0N/A */
0N/A
0N/A for (int i = nvert - 1; --i >= 0;) {
0N/A boolean flipped = false;
0N/A for (int j = 0; j <= i; j++) {
0N/A int a = zs[j];
0N/A int b = zs[j + 1];
0N/A if (v[a + 2] > v[b + 2]) {
0N/A zs[j + 1] = a;
0N/A zs[j] = b;
0N/A flipped = true;
0N/A }
0N/A }
3845N/A if (!flipped) {
0N/A break;
3845N/A }
0N/A }
0N/A
0N/A int lim = nvert;
3845N/A if (lim <= 0 || nvert <= 0) {
0N/A return;
3845N/A }
0N/A for (int i = 0; i < lim; i++) {
0N/A int j = zs[i];
0N/A int grey = v[j + 2];
3845N/A if (grey < 0) {
0N/A grey = 0;
3845N/A }
3845N/A if (grey > 15) {
0N/A grey = 15;
3845N/A }
0N/A // g.drawString(names[i], v[j], v[j+1]);
3845N/A atoms[j / 3].paint(g, v[j], v[j + 1], grey);
0N/A // g.drawImage(iBall, v[j] - (iBall.width >> 1), v[j + 1] -
0N/A // (iBall.height >> 1));
0N/A }
0N/A }
0N/A
0N/A /** Find the bounding box of this model */
0N/A void findBB() {
3845N/A if (nvert <= 0) {
0N/A return;
3845N/A }
0N/A float v[] = vert;
3845N/A float _xmin = v[0], _xmax = _xmin;
3845N/A float _ymin = v[1], _ymax = _ymin;
3845N/A float _zmin = v[2], _zmax = _zmin;
0N/A for (int i = nvert * 3; (i -= 3) > 0;) {
0N/A float x = v[i];
3845N/A if (x < _xmin) {
3845N/A _xmin = x;
3845N/A }
3845N/A if (x > _xmax) {
3845N/A _xmax = x;
3845N/A }
0N/A float y = v[i + 1];
3845N/A if (y < _ymin) {
3845N/A _ymin = y;
3845N/A }
3845N/A if (y > _ymax) {
3845N/A _ymax = y;
3845N/A }
0N/A float z = v[i + 2];
3845N/A if (z < _zmin) {
3845N/A _zmin = z;
3845N/A }
3845N/A if (z > _zmax) {
3845N/A _zmax = z;
3845N/A }
0N/A }
3845N/A this.xmax = _xmax;
3845N/A this.xmin = _xmin;
3845N/A this.ymax = _ymax;
3845N/A this.ymin = _ymin;
3845N/A this.zmax = _zmax;
3845N/A this.zmin = _zmin;
0N/A }
0N/A}
0N/A
3845N/A
0N/A/** An applet to put a Chemical model into a page */
3845N/A@SuppressWarnings("serial")
3845N/Apublic class XYZApp extends Applet implements Runnable, MouseListener,
3845N/A MouseMotionListener {
3845N/A
0N/A XYZChemModel md;
0N/A boolean painted = true;
0N/A float xfac;
0N/A int prevx, prevy;
0N/A float scalefudge = 1;
0N/A Matrix3D amat = new Matrix3D(), tmat = new Matrix3D();
0N/A String mdname = null;
0N/A String message = null;
0N/A Image backBuffer;
0N/A Graphics backGC;
0N/A Dimension backSize;
0N/A
0N/A private synchronized void newBackBuffer() {
0N/A backBuffer = createImage(getSize().width, getSize().height);
0N/A if (backGC != null) {
0N/A backGC.dispose();
0N/A }
0N/A backGC = backBuffer.getGraphics();
0N/A backSize = getSize();
0N/A }
0N/A
3845N/A @Override
0N/A public void init() {
0N/A mdname = getParameter("model");
0N/A try {
0N/A scalefudge = Float.valueOf(getParameter("scale")).floatValue();
3845N/A } catch (Exception ignored) {
3845N/A }
0N/A amat.yrot(20);
0N/A amat.xrot(20);
3845N/A if (mdname == null) {
0N/A mdname = "model.obj";
3845N/A }
0N/A resize(getSize().width <= 20 ? 400 : getSize().width,
3845N/A getSize().height <= 20 ? 400 : getSize().height);
0N/A newBackBuffer();
0N/A addMouseListener(this);
0N/A addMouseMotionListener(this);
0N/A }
0N/A
3845N/A @Override
0N/A public void destroy() {
0N/A removeMouseListener(this);
0N/A removeMouseMotionListener(this);
0N/A }
0N/A
3845N/A @Override
0N/A public void run() {
0N/A InputStream is = null;
0N/A try {
0N/A Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
0N/A is = new URL(getDocumentBase(), mdname).openStream();
3845N/A XYZChemModel m = new XYZChemModel(is);
0N/A Atom.setApplet(this);
0N/A md = m;
0N/A m.findBB();
0N/A float xw = m.xmax - m.xmin;
0N/A float yw = m.ymax - m.ymin;
0N/A float zw = m.zmax - m.zmin;
3845N/A if (yw > xw) {
0N/A xw = yw;
3845N/A }
3845N/A if (zw > xw) {
0N/A xw = zw;
3845N/A }
0N/A float f1 = getSize().width / xw;
0N/A float f2 = getSize().height / xw;
0N/A xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge;
3845N/A } catch (Exception e) {
3845N/A Logger.getLogger(XYZApp.class.getName()).log(Level.SEVERE, null, e);
0N/A md = null;
0N/A message = e.toString();
0N/A }
0N/A try {
3845N/A if (is != null) {
0N/A is.close();
3845N/A }
3845N/A } catch (Exception ignored) {
0N/A }
0N/A repaint();
0N/A }
3845N/A
3845N/A @Override
0N/A public void start() {
3845N/A if (md == null && message == null) {
0N/A new Thread(this).start();
3845N/A }
0N/A }
3845N/A
3845N/A @Override
0N/A public void stop() {
0N/A }
3845N/A /* event handling */
3845N/A
3845N/A @Override
3845N/A public void mouseClicked(MouseEvent e) {
3845N/A }
3845N/A
3845N/A @Override
3845N/A public void mousePressed(MouseEvent e) {
3845N/A prevx = e.getX();
3845N/A prevy = e.getY();
3845N/A e.consume();
3845N/A }
3845N/A
3845N/A @Override
3845N/A public void mouseReleased(MouseEvent e) {
3845N/A }
3845N/A
3845N/A @Override
3845N/A public void mouseEntered(MouseEvent e) {
3845N/A }
3845N/A
3845N/A @Override
3845N/A public void mouseExited(MouseEvent e) {
0N/A }
0N/A
3845N/A @Override
3845N/A public void mouseDragged(MouseEvent e) {
3845N/A int x = e.getX();
3845N/A int y = e.getY();
3845N/A tmat.unit();
3845N/A float xtheta = (prevy - y) * (360.0f / getSize().width);
3845N/A float ytheta = (x - prevx) * (360.0f / getSize().height);
3845N/A tmat.xrot(xtheta);
3845N/A tmat.yrot(ytheta);
3845N/A amat.mult(tmat);
3845N/A if (painted) {
3845N/A painted = false;
3845N/A repaint();
3845N/A }
3845N/A prevx = x;
3845N/A prevy = y;
3845N/A e.consume();
3845N/A }
3845N/A
3845N/A @Override
3845N/A public void mouseMoved(MouseEvent e) {
3845N/A }
3845N/A
3845N/A @Override
0N/A public void update(Graphics g) {
3845N/A if (backBuffer == null) {
0N/A g.clearRect(0, 0, getSize().width, getSize().height);
3845N/A }
0N/A paint(g);
0N/A }
0N/A
3845N/A @Override
0N/A public void paint(Graphics g) {
0N/A if (md != null) {
0N/A md.mat.unit();
0N/A md.mat.translate(-(md.xmin + md.xmax) / 2,
3845N/A -(md.ymin + md.ymax) / 2,
3845N/A -(md.zmin + md.zmax) / 2);
0N/A md.mat.mult(amat);
0N/A // md.mat.scale(xfac, -xfac, 8 * xfac / getSize().width);
0N/A md.mat.scale(xfac, -xfac, 16 * xfac / getSize().width);
0N/A md.mat.translate(getSize().width / 2, getSize().height / 2, 8);
0N/A md.transformed = false;
0N/A if (backBuffer != null) {
3845N/A if (!backSize.equals(getSize())) {
0N/A newBackBuffer();
3845N/A }
0N/A backGC.setColor(getBackground());
3845N/A backGC.fillRect(0, 0, getSize().width, getSize().height);
0N/A md.paint(backGC);
0N/A g.drawImage(backBuffer, 0, 0, this);
3845N/A } else {
3845N/A md.paint(g);
0N/A }
0N/A setPainted();
0N/A } else if (message != null) {
0N/A g.drawString("Error in model:", 3, 20);
0N/A g.drawString(message, 10, 40);
0N/A }
0N/A }
3845N/A
0N/A private synchronized void setPainted() {
0N/A painted = true;
0N/A notifyAll();
0N/A }
0N/A
3845N/A @Override
3845N/A public String getAppletInfo() {
3845N/A return "Title: XYZApp \nAuthor: James Gosling \nAn applet to put"
3845N/A + " a Chemical model into a page.";
0N/A }
0N/A
3845N/A @Override
3845N/A public String[][] getParameterInfo() {
3845N/A String[][] info = {
3845N/A { "model", "path string", "The path to the model to be displayed"
3845N/A + " in .xyz format "
3845N/A + "(see http://chem.leeds.ac.uk/Project/MIME.html)."
3845N/A + " Default is model.obj." },
3845N/A { "scale", "float", "Scale factor. Default is 1 (i.e. no scale)." }
3845N/A };
3845N/A return info;
3845N/A }
0N/A} // end class XYZApp
0N/A
3845N/A
0N/Aclass Atom {
3845N/A
0N/A private static Applet applet;
0N/A private static byte[] data;
0N/A private final static int R = 40;
0N/A private final static int hx = 15;
0N/A private final static int hy = 15;
0N/A private final static int bgGrey = 192;
0N/A private final static int nBalls = 16;
0N/A private static int maxr;
0N/A private int Rl;
0N/A private int Gl;
0N/A private int Bl;
0N/A private Image balls[];
0N/A
0N/A static {
0N/A data = new byte[R * 2 * R * 2];
0N/A int mr = 0;
0N/A for (int Y = 2 * R; --Y >= 0;) {
0N/A int x0 = (int) (Math.sqrt(R * R - (Y - R) * (Y - R)) + 0.5);
0N/A int p = Y * (R * 2) + R - x0;
0N/A for (int X = -x0; X < x0; X++) {
0N/A int x = X + hx;
0N/A int y = Y - R + hy;
0N/A int r = (int) (Math.sqrt(x * x + y * y) + 0.5);
3845N/A if (r > mr) {
0N/A mr = r;
3845N/A }
0N/A data[p++] = r <= 0 ? 1 : (byte) r;
0N/A }
0N/A }
0N/A maxr = mr;
0N/A }
3845N/A
0N/A static void setApplet(Applet app) {
0N/A applet = app;
0N/A }
3845N/A
0N/A Atom(int Rl, int Gl, int Bl) {
0N/A this.Rl = Rl;
0N/A this.Gl = Gl;
0N/A this.Bl = Bl;
0N/A }
3845N/A
3845N/A private int blend(int fg, int bg, float fgfactor) {
0N/A return (int) (bg + (fg - bg) * fgfactor);
0N/A }
3845N/A
0N/A private void Setup() {
0N/A balls = new Image[nBalls];
0N/A byte red[] = new byte[256];
0N/A red[0] = (byte) bgGrey;
0N/A byte green[] = new byte[256];
0N/A green[0] = (byte) bgGrey;
0N/A byte blue[] = new byte[256];
0N/A blue[0] = (byte) bgGrey;
0N/A for (int r = 0; r < nBalls; r++) {
3845N/A float b = (float) (r + 1) / nBalls;
0N/A for (int i = maxr; i >= 1; --i) {
0N/A float d = (float) i / maxr;
0N/A red[i] = (byte) blend(blend(Rl, 255, d), bgGrey, b);
0N/A green[i] = (byte) blend(blend(Gl, 255, d), bgGrey, b);
0N/A blue[i] = (byte) blend(blend(Bl, 255, d), bgGrey, b);
0N/A }
0N/A IndexColorModel model = new IndexColorModel(8, maxr + 1,
3845N/A red, green, blue, 0);
0N/A balls[r] = applet.createImage(
3845N/A new MemoryImageSource(R * 2, R * 2, model, data, 0, R * 2));
0N/A }
0N/A }
3845N/A
0N/A void paint(Graphics gc, int x, int y, int r) {
0N/A Image ba[] = balls;
0N/A if (ba == null) {
0N/A Setup();
0N/A ba = balls;
0N/A }
0N/A Image i = ba[r];
0N/A int size = 10 + r;
0N/A gc.drawImage(i, x - (size >> 1), y - (size >> 1), size, size, applet);
0N/A }
0N/A}