home *** CD-ROM | disk | FTP | other *** search
Java Source | 1996-05-23 | 10.1 KB | 440 lines |
- // XYZComponent.java
- // A JFS component for displaying 3d chemical models in the XYZ format. The
- // code for this was mostly ripped out of the XYZApp applet that comes with
- // the JDK.
- import java.awt.image.*;
- import java.awt.*;
- import java.io.*;
- import java.util.Hashtable;
- import JFScomponent;
- import JFSclient;
- import FileReq;
- import DrawingPanel;
- import Drawing;
- import Matrix3D;
-
- public class XYZComponent extends JFScomponent
- {
- Button loadb;
- XYZCanvas canv;
- FileReq loadreq;
-
- XYZComponent()
- {
- setLayout(new BorderLayout());
-
- // Create top panel
- Panel top = new Panel();
- top.setLayout(new FlowLayout(FlowLayout.LEFT));
- top.add(loadb = new Button("Load"));
- add("North",top);
-
- // Create viewing canvas
- canv = new XYZCanvas();
- BorderPanel bot = new BorderPanel(new Color(50,50,50),
- new Color(220,220,220));
- bot.setLayout(new BorderLayout());
- bot.add("Center",canv);
- add("Center",bot);
- }
-
- public boolean action(Event evt, Object obj)
- {
- if (evt.target == loadb && loadreq == null) {
- // load button clicked
- loadreq = new FileReq(client, this, "Load", "chemistry/x-xyz",
- false, null);
- }
- else if (evt.target == loadreq) {
- // load requestor submitted / closed
- if (((String)evt.arg).equals("Load")) {
- // load a model
- try load(loadreq.getfile(), loadreq.getversion());
- catch(RequestException e)
- new ErrorWindow("Could not open "+
- loadreq.getfile()+" : "+
- e.getMessage());
- }
- loadreq = null;
- }
- return true;
- }
-
- // load
- // Load the given model for viewing
- void load(String file, int ver) throws RequestException
- {
- byte fd[] = client.get(file, ver);
- ByteArrayInputStream buf = new ByteArrayInputStream(fd);
- if (!canv.loadmodel(buf))
- throw new RequestException("Model format error");
- client.setcurrent(file);
- }
-
- Dimension wantedsize()
- {
- return new Dimension(400,400);
- }
- }
-
- /** The representation of a Chemical .xyz model */
- class XYZChemModel {
- float vert[];
- Atom atoms[];
- int tvert[];
- int ZsortMap[];
- int nvert, maxvert;
-
- static Hashtable atomTable = new Hashtable();
- static Atom defaultAtom;
- static {
- atomTable.put("c", new Atom(0, 0, 0));
- atomTable.put("h", new Atom(210, 210, 210));
- atomTable.put("n", new Atom(0, 0, 255));
- atomTable.put("o", new Atom(255, 0, 0));
- atomTable.put("p", new Atom(255, 0, 255));
- atomTable.put("s", new Atom(255, 255, 0));
- atomTable.put("hn", new Atom(150, 255, 150)); /* !!*/
- defaultAtom = new Atom(255, 100, 200);
- }
-
- boolean transformed;
- Matrix3D mat;
-
- float xmin, xmax, ymin, ymax, zmin, zmax;
-
-
- XYZChemModel () {
- mat = new Matrix3D();
- mat.xrot(20);
- mat.yrot(30);
- }
-
-
- /** Create a Cehmical model by parsing an input stream */
- XYZChemModel (InputStream is) throws Exception {
- this();
- StreamTokenizer st = new StreamTokenizer(new BufferedInputStream(is, 4000));
- st.eolIsSignificant(true);
- st.commentChar('#');
- int slot = 0;
- scan:
- while (true)
- switch (st.nextToken()) {
- case StreamTokenizer.TT_EOF:
- break scan;
- default:
- break;
- case StreamTokenizer.TT_WORD:
- String name = st.sval;
- double x = 0, y = 0, z = 0;
- if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
- x = st.nval;
- if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
- y = st.nval;
- if (st.nextToken() == StreamTokenizer.TT_NUMBER)
- z = st.nval;
- }
- }
- addVert(name, (float) x, (float) y, (float) z);
- while (st.ttype != StreamTokenizer.TT_EOL &&
- st.ttype != StreamTokenizer.TT_EOF)
- st.nextToken();
- }
- is.close();
- if (st.ttype != StreamTokenizer.TT_EOF)
- throw new Exception(st.toString());
- }
-
- /** Add a vertex to this model */
- int addVert(String name, float x, float y, float z) {
- int i = nvert;
- if (i >= maxvert)
- if (vert == null) {
- maxvert = 100;
- vert = new float[maxvert * 3];
- atoms = new Atom[maxvert];
- } else {
- maxvert *= 2;
- float nv[] = new float[maxvert * 3];
- System.arraycopy(vert, 0, nv, 0, vert.length);
- vert = nv;
- Atom na[] = new Atom[maxvert];
- System.arraycopy(atoms, 0, na, 0, atoms.length);
- atoms = na;
- }
- Atom a = (Atom) atomTable.get(name.toLowerCase());
- if (a == null) a = defaultAtom;
- atoms[i] = a;
- i *= 3;
- vert[i] = x;
- vert[i + 1] = y;
- vert[i + 2] = z;
- return nvert++;
- }
-
- /** Transform all the points in this model */
- void transform() {
- if (transformed || nvert <= 0)
- return;
- if (tvert == null || tvert.length < nvert * 3)
- tvert = new int[nvert * 3];
- mat.transform(vert, tvert, nvert);
- transformed = true;
- }
-
-
- /** Paint this model to a graphics context. It uses the matrix associated
- with this model to map from model space to screen space.
- The next version of the browser should have double buffering,
- which will make this *much* nicer */
- void paint(Graphics g, Component parent) {
- if (vert == null || nvert <= 0)
- return;
- transform();
- int v[] = tvert;
- int zs[] = ZsortMap;
- if (zs == null) {
- ZsortMap = zs = new int[nvert];
- for (int i = nvert; --i >= 0;)
- zs[i] = i * 3;
- }
-
- /*
- * I use a bubble sort since from one iteration to the next, the sort
- * order is pretty stable, so I just use what I had last time as a
- * "guess" of the sorted order. With luck, this reduces O(N log N)
- * to O(N)
- */
-
- for (int i = nvert - 1; --i >= 0;) {
- boolean flipped = false;
- for (int j = 0; j <= i; j++) {
- int a = zs[j];
- int b = zs[j + 1];
- if (v[a + 2] > v[b + 2]) {
- zs[j + 1] = a;
- zs[j] = b;
- flipped = true;
- }
- }
- if (!flipped)
- break;
- }
-
- int lg = 0;
- int lim = nvert;
- Atom ls[] = atoms;
- if (lim <= 0 || nvert <= 0)
- return;
- for (int i = 0; i < lim; i++) {
- int j = zs[i];
- int grey = v[j + 2];
- if (grey < 0)
- grey = 0;
- if (grey > 15)
- grey = 15;
- // g.drawString(names[i], v[j], v[j+1]);
- atoms[j/3].paint(g, v[j], v[j + 1], grey, parent);
- // g.drawImage(iBall, v[j] - (iBall.width >> 1), v[j + 1] -
- // (iBall.height >> 1));
- }
- }
-
- /** Find the bounding box of this model */
- void findBB() {
- if (nvert <= 0)
- return;
- float v[] = vert;
- float xmin = v[0], xmax = xmin;
- float ymin = v[1], ymax = ymin;
- float zmin = v[2], zmax = zmin;
- for (int i = nvert * 3; (i -= 3) > 0;) {
- float x = v[i];
- if (x < xmin)
- xmin = x;
- if (x > xmax)
- xmax = x;
- float y = v[i + 1];
- if (y < ymin)
- ymin = y;
- if (y > ymax)
- ymax = y;
- float z = v[i + 2];
- if (z < zmin)
- zmin = z;
- if (z > zmax)
- zmax = z;
- }
- this.xmax = xmax;
- this.xmin = xmin;
- this.ymax = ymax;
- this.ymin = ymin;
- this.zmax = zmax;
- this.zmin = zmin;
- }
- }
-
- // XYZCanvas
- // Where the actual drawing takes place
- class XYZCanvas extends Canvas {
- XYZChemModel md;
- float xfac;
- int prevx, prevy;
- float xtheta, ytheta;
- float scalefudge = 1;
- Matrix3D amat = new Matrix3D(), tmat = new Matrix3D();
- Image dbuf;
-
- // loadmodel
- // Read a model to use from the given stream
- boolean loadmodel(InputStream is)
- {
- try {
- XYZChemModel m = new XYZChemModel (is);
- md = m;
- m.findBB();
- dbuf = null; // force rescale
- }
- catch(Exception e)
- return false;
- paint(getGraphics());
- return true;
- }
-
- public boolean mouseDown(Event e, int x, int y)
- {
- prevx = x;
- prevy = y;
- return true;
- }
-
- public boolean mouseDrag(Event e, int x, int y)
- {
- tmat.unit();
- float xtheta = (prevy - y) * (360.0f / size().width);
- float ytheta = (x - prevx) * (360.0f / size().height);
- tmat.xrot(xtheta);
- tmat.yrot(ytheta);
- amat.mult(tmat);
- repaint();
- prevx = x;
- prevy = y;
- return true;
- }
-
- public void update(Graphics g)
- {
- paint(g);
- }
-
- public void paint(Graphics fg)
- {
- if (fg == null)
- return; // not visible yet
- if (dbuf == null || dbuf.getWidth(this) != size().width ||
- dbuf.getHeight(this) != size().height) {
- // we have been resized
- dbuf = createImage(size().width, size().height);
- float xw = md.xmax - md.xmin;
- float yw = md.ymax - md.ymin;
- float zw = md.zmax - md.zmin;
- if (yw > xw)
- xw = yw;
- if (zw > xw)
- xw = zw;
- float f1 = size().width / xw;
- float f2 = size().height / xw;
- xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge;
- }
- Graphics g = dbuf.getGraphics();
- g.setColor(Color.lightGray);
- g.fillRect(0, 0, size().width, size().height);
- if (md != null) {
- md.mat.unit();
- md.mat.translate(-(md.xmin + md.xmax) / 2,
- -(md.ymin + md.ymax) / 2,
- -(md.zmin + md.zmax) / 2);
- md.mat.mult(amat);
- md.mat.scale(xfac, -xfac, 16 * xfac / size().width);
- md.mat.translate(size().width / 2, size().height / 2, 8);
- md.transformed = false;
- md.paint(g, this);
- }
- fg.drawImage(dbuf, 0, 0, this);
- }
- }
-
- class Atom {
- private static byte[] data;
- private final static int R = 40;
- private final static int hx = 15;
- private final static int hy = 15;
- private final static int bgGrey = 192;
- private final static int nBalls = 16;
- private static int maxr;
-
- private int Rl;
- private int Gl;
- private int Bl;
- private Image balls[];
-
- static {
- data = new byte[R * 2 * R * 2];
- int mr = 0;
- for (int Y = 2 * R; --Y >= 0;) {
- int x0 = (int) (Math.sqrt(R * R - (Y - R) * (Y - R)) + 0.5);
- int p = Y * (R * 2) + R - x0;
- for (int X = -x0; X < x0; X++) {
- int x = X + hx;
- int y = Y - R + hy;
- int r = (int) (Math.sqrt(x * x + y * y) + 0.5);
- if (r > mr)
- mr = r;
- data[p++] = r <= 0 ? 1 : (byte) r;
- }
- }
- maxr = mr;
- }
- Atom(int Rl, int Gl, int Bl) {
- this.Rl = Rl;
- this.Gl = Gl;
- this.Bl = Bl;
- }
- private final int blend(int fg, int bg, float fgfactor) {
- return (int) (bg + (fg - bg) * fgfactor);
- }
- private void Setup(Component parent) {
- balls = new Image[nBalls];
- byte red[] = new byte[256];
- red[0] = (byte) bgGrey;
- byte green[] = new byte[256];
- green[0] = (byte) bgGrey;
- byte blue[] = new byte[256];
- blue[0] = (byte) bgGrey;
- for (int r = 0; r < nBalls; r++) {
- float b = (float) (r+1) / nBalls;
- for (int i = maxr; i >= 1; --i) {
- float d = (float) i / maxr;
- red[i] = (byte) blend(blend(Rl, 255, d), bgGrey, b);
- green[i] = (byte) blend(blend(Gl, 255, d), bgGrey, b);
- blue[i] = (byte) blend(blend(Bl, 255, d), bgGrey, b);
- }
- IndexColorModel model = new IndexColorModel(8, maxr + 1,
- red, green, blue, 0);
- balls[r] = parent.createImage(
- new MemoryImageSource(R*2, R*2, model, data, 0, R*2));
- }
- }
- void paint(Graphics gc, int x, int y, int r, Component parent) {
- Image ba[] = balls;
- if (ba == null) {
- Setup(parent);
- ba = balls;
- }
- Image i = ba[r];
- int size = 10 + r;
- gc.drawImage(i, x - (size >> 1), y - (size >> 1), size, size, parent);
- }
- }
-