Back to index

wims  3.65+svn20090927
XYZApp.java
Go to the documentation of this file.
00001 /*
00002  * @(#)XYZApp.java
00003  *
00004  * Copyright (c) 1994-1996 Sun Microsystems, Inc. All Rights Reserved.
00005  *
00006  * Permission to use, copy, modify, and distribute this software
00007  * and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
00008  * without fee is hereby granted. 
00009  * Please refer to the file http://java.sun.com/copy_trademarks.html
00010  * for further important copyright and trademark information and to
00011  * http://java.sun.com/licensing.html for further important licensing
00012  * information for the Java (tm) Technology.
00013  * 
00014  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
00015  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
00016  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
00017  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
00018  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
00019  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
00020  * 
00021  * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
00022  * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
00023  * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
00024  * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
00025  * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
00026  * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
00027  * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES").  SUN
00028  * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
00029  * HIGH RISK ACTIVITIES.
00030  */
00031 
00032 import java.applet.Applet;
00033 import java.awt.Image;
00034 import java.awt.Event;
00035 import java.awt.Graphics;
00036 import java.io.StreamTokenizer;
00037 import java.io.InputStream;
00038 import java.io.BufferedInputStream;
00039 import java.net.URL;
00040 import java.util.Hashtable;
00041 import java.awt.image.IndexColorModel;
00042 import java.awt.image.ColorModel;
00043 import java.awt.image.MemoryImageSource;
00044 
00045 
00047 class XYZChemModel {
00048     float vert[];
00049     Atom atoms[];
00050     int tvert[];
00051     int ZsortMap[];
00052     int nvert, maxvert;
00053 
00054     static Hashtable atomTable = new Hashtable();
00055     static Atom defaultAtom;
00056     static {
00057        atomTable.put("c", new Atom(0, 0, 0));
00058        atomTable.put("x", new Atom(176, 160, 240));
00059        atomTable.put("h", new Atom(210, 210, 210));
00060        atomTable.put("n", new Atom(0, 0, 255));
00061        atomTable.put("o", new Atom(255, 0, 0));
00062        atomTable.put("p", new Atom(255, 0, 255));
00063        atomTable.put("s", new Atom(255, 255, 0));
00064        atomTable.put("hn", new Atom(150, 255, 150)); /* !!*/
00065        defaultAtom = new Atom(255, 100, 200);
00066     }
00067 
00068     boolean transformed;
00069     Matrix3D mat;
00070 
00071     float xmin, xmax, ymin, ymax, zmin, zmax;
00072 
00073 
00074     XYZChemModel () {
00075        mat = new Matrix3D();
00076        mat.xrot(20);
00077        mat.yrot(30);
00078     }
00079 
00080 
00082     XYZChemModel (InputStream is) throws Exception {
00083        this();
00084        StreamTokenizer st = new StreamTokenizer(new BufferedInputStream(is, 4000));
00085        st.eolIsSignificant(true);
00086        st.commentChar('#');
00087        int slot = 0;
00088 scan:
00089        while (true)
00090            switch (st.nextToken()) {
00091              case StreamTokenizer.TT_EOF:
00092               break scan;
00093              default:
00094               break;
00095              case StreamTokenizer.TT_WORD:
00096               String name = st.sval;
00097               double x = 0, y = 0, z = 0;
00098               if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
00099                   x = st.nval;
00100                   if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
00101                      y = st.nval;
00102                      if (st.nextToken() == StreamTokenizer.TT_NUMBER)
00103                          z = st.nval;
00104                   }
00105               }
00106               addVert(name, (float) x, (float) y, (float) z);
00107               while (st.ttype != StreamTokenizer.TT_EOL &&
00108                      st.ttype != StreamTokenizer.TT_EOF)
00109                   st.nextToken();
00110            }
00111        is.close();
00112        if (st.ttype != StreamTokenizer.TT_EOF)
00113            throw new Exception(st.toString());
00114     }
00115 
00117     int addVert(String name, float x, float y, float z) {
00118        int i = nvert;
00119        if (i >= maxvert)
00120            if (vert == null) {
00121               maxvert = 100;
00122               vert = new float[maxvert * 3];
00123               atoms = new Atom[maxvert];
00124            } else {
00125               maxvert *= 2;
00126               float nv[] = new float[maxvert * 3];
00127               System.arraycopy(vert, 0, nv, 0, vert.length);
00128               vert = nv;
00129               Atom na[] = new Atom[maxvert];
00130               System.arraycopy(atoms, 0, na, 0, atoms.length);
00131               atoms = na;
00132            }
00133        Atom a = (Atom) atomTable.get(name.toLowerCase());
00134        if (a == null) a = defaultAtom;
00135        atoms[i] = a;
00136        i *= 3;
00137        vert[i] = x;
00138        vert[i + 1] = y;
00139        vert[i + 2] = z;
00140        return nvert++;
00141     }
00142 
00144     void transform() {
00145        if (transformed || nvert <= 0)
00146            return;
00147        if (tvert == null || tvert.length < nvert * 3)
00148            tvert = new int[nvert * 3];
00149        mat.transform(vert, tvert, nvert);
00150        transformed = true;
00151     }
00152 
00153 
00158     void paint(Graphics g) {
00159        if (vert == null || nvert <= 0)
00160            return;
00161        transform();
00162        int v[] = tvert;
00163        int zs[] = ZsortMap;
00164        if (zs == null) {
00165            ZsortMap = zs = new int[nvert];
00166            for (int i = nvert; --i >= 0;)
00167               zs[i] = i * 3;
00168        }
00169 
00170        /*
00171         * I use a bubble sort since from one iteration to the next, the sort
00172         * order is pretty stable, so I just use what I had last time as a
00173         * "guess" of the sorted order.  With luck, this reduces O(N log N)
00174         * to O(N)
00175         */
00176 
00177        for (int i = nvert - 1; --i >= 0;) {
00178            boolean flipped = false;
00179            for (int j = 0; j <= i; j++) {
00180               int a = zs[j];
00181               int b = zs[j + 1];
00182               if (v[a + 2] > v[b + 2]) {
00183                   zs[j + 1] = a;
00184                   zs[j] = b;
00185                   flipped = true;
00186               }
00187            }
00188            if (!flipped)
00189               break;
00190        }
00191 
00192        int lg = 0;
00193        int lim = nvert;
00194        Atom ls[] = atoms;
00195        if (lim <= 0 || nvert <= 0)
00196            return;
00197        for (int i = 0; i < lim; i++) {
00198            int j = zs[i];
00199            int grey = v[j + 2];
00200            if (grey < 0)
00201               grey = 0;
00202            if (grey > 15)
00203               grey = 15;
00204            // g.drawString(names[i], v[j], v[j+1]);
00205            atoms[j/3].paint(g, v[j], v[j + 1], grey);
00206            // g.drawImage(iBall, v[j] - (iBall.width >> 1), v[j + 1] -
00207            // (iBall.height >> 1));
00208        }
00209     }
00210 
00212     void findBB() {
00213        if (nvert <= 0)
00214            return;
00215        float v[] = vert;
00216        float xmin = v[0], xmax = xmin;
00217        float ymin = v[1], ymax = ymin;
00218        float zmin = v[2], zmax = zmin;
00219        for (int i = nvert * 3; (i -= 3) > 0;) {
00220            float x = v[i];
00221            if (x < xmin)
00222               xmin = x;
00223            if (x > xmax)
00224               xmax = x;
00225            float y = v[i + 1];
00226            if (y < ymin)
00227               ymin = y;
00228            if (y > ymax)
00229               ymax = y;
00230            float z = v[i + 2];
00231            if (z < zmin)
00232               zmin = z;
00233            if (z > zmax)
00234               zmax = z;
00235        }
00236        this.xmax = xmax;
00237        this.xmin = xmin;
00238        this.ymax = ymax;
00239        this.ymin = ymin;
00240        this.zmax = zmax;
00241        this.zmin = zmin;
00242     }
00243 }
00244 
00246 public class XYZApp extends Applet implements Runnable {
00247     XYZChemModel md;
00248     boolean painted = true;
00249     float xfac;
00250     int prevx, prevy;
00251     float xtheta, ytheta;
00252     float scalefudge = 1;
00253     Matrix3D amat = new Matrix3D(), tmat = new Matrix3D();
00254     String mdname = null;
00255     String message = null;
00256     Image backBuffer;
00257     Graphics backGC;
00258 
00259 
00260     public void init() {
00261        mdname = getParameter("model");
00262        try {
00263            scalefudge = Float.valueOf(getParameter("scale")).floatValue();
00264        } catch(Exception e) {
00265        };
00266        amat.yrot(20);
00267        amat.xrot(20);
00268        if (mdname == null)
00269            mdname = "model.obj";
00270        resize(size().width <= 20 ? 400 : size().width,
00271               size().height <= 20 ? 400 : size().height);
00272     }
00273     public void run() {
00274        InputStream is = null;
00275        try {
00276            Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
00277            is = new URL(getDocumentBase(), mdname).openStream();
00278            XYZChemModel m = new XYZChemModel (is);
00279            Atom.setApplet(this);
00280            md = m;
00281            m.findBB();
00282            float xw = m.xmax - m.xmin;
00283            float yw = m.ymax - m.ymin;
00284            float zw = m.zmax - m.zmin;
00285            if (yw > xw)
00286               xw = yw;
00287            if (zw > xw)
00288               xw = zw;
00289            float f1 = size().width / xw;
00290            float f2 = size().height / xw;
00291            xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge;
00292            backBuffer = createImage(size().width, size().height);
00293            backGC = backBuffer.getGraphics();
00294        } catch(Exception e) {
00295            e.printStackTrace();
00296            md = null;
00297            message = e.toString();
00298        }
00299        try {
00300            if (is != null)
00301               is.close();
00302        } catch(Exception e) {
00303        }
00304        repaint();
00305     }
00306     public void start() {
00307        if (md == null && message == null)
00308            new Thread(this).start();
00309     }
00310     public void stop() {
00311     }
00312     public boolean mouseDown(Event e, int x, int y) {
00313        prevx = x;
00314        prevy = y;
00315        return true;
00316     }
00317     public boolean mouseDrag(Event e, int x, int y) {
00318        tmat.unit();
00319        float xtheta = (prevy - y) * (360.0f / size().width);
00320        float ytheta = (x - prevx) * (360.0f / size().height);
00321        tmat.xrot(xtheta);
00322        tmat.yrot(ytheta);
00323        amat.mult(tmat);
00324        if (painted) {
00325            painted = false;
00326            repaint();
00327        }
00328        prevx = x;
00329        prevy = y;
00330        return true;
00331     }
00332     public void update(Graphics g) {
00333        if (backBuffer == null)
00334            g.clearRect(0, 0, size().width, size().height);
00335        paint(g);
00336     }
00337     public void paint(Graphics g) {
00338        if (md != null) {
00339            md.mat.unit();
00340            md.mat.translate(-(md.xmin + md.xmax) / 2,
00341                           -(md.ymin + md.ymax) / 2,
00342                           -(md.zmin + md.zmax) / 2);
00343            md.mat.mult(amat);
00344            // md.mat.scale(xfac, -xfac, 8 * xfac / size().width);
00345            md.mat.scale(xfac, -xfac, 16 * xfac / size().width);
00346            md.mat.translate(size().width / 2, size().height / 2, 8);
00347            md.transformed = false;
00348            if (backBuffer != null) {
00349               backGC.setColor(getBackground());
00350               backGC.fillRect(0,0,size().width,size().height);
00351               md.paint(backGC);
00352               g.drawImage(backBuffer, 0, 0, this);
00353            } else
00354               md.paint(g);
00355            setPainted();
00356        } else if (message != null) {
00357            g.drawString("Error in model:", 3, 20);
00358            g.drawString(message, 10, 40);
00359        }
00360     }
00361     private synchronized void setPainted() {
00362        painted = true;
00363        notifyAll();
00364     }
00365     private synchronized void waitPainted() {
00366        while (!painted)
00367            try { wait(); } catch (Exception e) {}
00368        painted = false;
00369     }
00370 }
00371 
00372 class Atom {
00373     private static Applet applet;
00374     private static byte[] data;
00375     private final static int R = 40;
00376     private final static int hx = 15;
00377     private final static int hy = 15;
00378     private final static int bgGrey = 192;
00379     private final static int nBalls = 16;
00380     private static int maxr;
00381 
00382     private int Rl;
00383     private int Gl;
00384     private int Bl;
00385     private Image balls[];
00386 
00387     static {
00388        data = new byte[R * 2 * R * 2];
00389        int mr = 0;
00390        for (int Y = 2 * R; --Y >= 0;) {
00391            int x0 = (int) (Math.sqrt(R * R - (Y - R) * (Y - R)) + 0.5);
00392            int p = Y * (R * 2) + R - x0;
00393            for (int X = -x0; X < x0; X++) {
00394               int x = X + hx;
00395               int y = Y - R + hy;
00396               int r = (int) (Math.sqrt(x * x + y * y) + 0.5);
00397               if (r > mr)
00398                   mr = r;
00399               data[p++] = r <= 0 ? 1 : (byte) r;
00400            }
00401        }
00402        maxr = mr;
00403     }
00404     static void setApplet(Applet app) {
00405        applet = app;
00406     }
00407     Atom(int Rl, int Gl, int Bl) {
00408        this.Rl = Rl;
00409        this.Gl = Gl;
00410        this.Bl = Bl;
00411     }
00412     private final int blend(int fg, int bg, float fgfactor) {
00413        return (int) (bg + (fg - bg) * fgfactor);
00414     }
00415     private void Setup() {
00416        balls = new Image[nBalls];
00417        byte red[] = new byte[256];
00418        red[0] = (byte) bgGrey;
00419        byte green[] = new byte[256];
00420        green[0] = (byte) bgGrey;
00421        byte blue[] = new byte[256];
00422        blue[0] = (byte) bgGrey;
00423        for (int r = 0; r < nBalls; r++) {
00424            float b = (float) (r+1) / nBalls;
00425            for (int i = maxr; i >= 1; --i) {
00426               float d = (float) i / maxr;
00427               red[i] = (byte) blend(blend(Rl, 255, d), bgGrey, b);
00428               green[i] = (byte) blend(blend(Gl, 255, d), bgGrey, b);
00429               blue[i] = (byte) blend(blend(Bl, 255, d), bgGrey, b);
00430            }
00431            IndexColorModel model = new IndexColorModel(8, maxr + 1,
00432                                                  red, green, blue, 0);
00433            balls[r] = applet.createImage(
00434               new MemoryImageSource(R*2, R*2, model, data, 0, R*2));
00435        }
00436     }
00437     void paint(Graphics gc, int x, int y, int r) {
00438        Image ba[] = balls;
00439        if (ba == null) {
00440            Setup();
00441            ba = balls;
00442        }
00443        Image i = ba[r];
00444        int size = 10 + r;
00445        gc.drawImage(i, x - (size >> 1), y - (size >> 1), size, size, applet);
00446     }
00447 }