home *** CD-ROM | disk | FTP | other *** search
/ Java Developer's Companion / Java Developer's Companion.iso / Javacup / PR8ADPL7.TAR / productivity_tools / PR8ADPL7 / XYZComponent.java < prev   
Encoding:
Java Source  |  1996-05-23  |  10.1 KB  |  440 lines

  1. // XYZComponent.java
  2. // A JFS component for displaying 3d chemical models in the XYZ format. The
  3. // code for this was mostly ripped out of the XYZApp applet that comes with
  4. // the JDK.
  5. import java.awt.image.*;
  6. import java.awt.*;
  7. import java.io.*;
  8. import java.util.Hashtable;
  9. import JFScomponent;
  10. import JFSclient;
  11. import FileReq;
  12. import DrawingPanel;
  13. import Drawing;
  14. import Matrix3D;
  15.  
  16. public class XYZComponent extends JFScomponent
  17. {
  18.     Button loadb;
  19.     XYZCanvas canv;
  20.     FileReq loadreq;
  21.  
  22.     XYZComponent()
  23.     {
  24.     setLayout(new BorderLayout());
  25.  
  26.     // Create top panel
  27.     Panel top = new Panel();
  28.     top.setLayout(new FlowLayout(FlowLayout.LEFT));
  29.     top.add(loadb = new Button("Load"));
  30.     add("North",top);
  31.  
  32.     // Create viewing canvas
  33.     canv = new XYZCanvas();
  34.     BorderPanel bot = new BorderPanel(new Color(50,50,50),
  35.                       new Color(220,220,220));
  36.     bot.setLayout(new BorderLayout());
  37.     bot.add("Center",canv);
  38.     add("Center",bot);
  39.     }
  40.  
  41.     public boolean action(Event evt, Object obj)
  42.     {
  43.     if (evt.target == loadb && loadreq == null) {
  44.         // load button clicked
  45.         loadreq = new FileReq(client, this, "Load", "chemistry/x-xyz",
  46.                       false, null);
  47.         }
  48.     else if (evt.target == loadreq) {
  49.         // load requestor submitted / closed
  50.         if (((String)evt.arg).equals("Load")) {
  51.             // load a model
  52.             try load(loadreq.getfile(), loadreq.getversion());
  53.             catch(RequestException e)
  54.                 new ErrorWindow("Could not open "+
  55.                         loadreq.getfile()+" : "+
  56.                         e.getMessage());
  57.             }
  58.         loadreq = null;
  59.         }
  60.     return true;
  61.     }
  62.  
  63.     // load
  64.     // Load the given model for viewing
  65.     void load(String file, int ver) throws RequestException
  66.     {
  67.     byte fd[] = client.get(file, ver);
  68.     ByteArrayInputStream buf = new ByteArrayInputStream(fd);
  69.     if (!canv.loadmodel(buf))
  70.         throw new RequestException("Model format error");
  71.     client.setcurrent(file);
  72.     }
  73.  
  74.     Dimension wantedsize()
  75.     {
  76.     return new Dimension(400,400);
  77.     }
  78. }
  79.  
  80. /** The representation of a Chemical .xyz model */
  81. class XYZChemModel {
  82.     float vert[];
  83.     Atom atoms[];
  84.     int tvert[];
  85.     int ZsortMap[];
  86.     int nvert, maxvert;
  87.  
  88.     static Hashtable atomTable = new Hashtable();
  89.     static Atom defaultAtom;
  90.     static {
  91.     atomTable.put("c", new Atom(0, 0, 0));
  92.     atomTable.put("h", new Atom(210, 210, 210));
  93.     atomTable.put("n", new Atom(0, 0, 255));
  94.     atomTable.put("o", new Atom(255, 0, 0));
  95.     atomTable.put("p", new Atom(255, 0, 255));
  96.     atomTable.put("s", new Atom(255, 255, 0));
  97.     atomTable.put("hn", new Atom(150, 255, 150)); /* !!*/
  98.     defaultAtom = new Atom(255, 100, 200);
  99.     }
  100.  
  101.     boolean transformed;
  102.     Matrix3D mat;
  103.  
  104.     float xmin, xmax, ymin, ymax, zmin, zmax;
  105.  
  106.  
  107.     XYZChemModel () {
  108.     mat = new Matrix3D();
  109.     mat.xrot(20);
  110.     mat.yrot(30);
  111.     }
  112.  
  113.  
  114.     /** Create a Cehmical model by parsing an input stream */
  115.     XYZChemModel (InputStream is) throws Exception {
  116.     this();
  117.     StreamTokenizer st = new StreamTokenizer(new BufferedInputStream(is, 4000));
  118.     st.eolIsSignificant(true);
  119.     st.commentChar('#');
  120.     int slot = 0;
  121. scan:
  122.     while (true)
  123.         switch (st.nextToken()) {
  124.           case StreamTokenizer.TT_EOF:
  125.         break scan;
  126.           default:
  127.         break;
  128.           case StreamTokenizer.TT_WORD:
  129.         String name = st.sval;
  130.         double x = 0, y = 0, z = 0;
  131.         if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
  132.             x = st.nval;
  133.             if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
  134.             y = st.nval;
  135.             if (st.nextToken() == StreamTokenizer.TT_NUMBER)
  136.                 z = st.nval;
  137.             }
  138.         }
  139.         addVert(name, (float) x, (float) y, (float) z);
  140.         while (st.ttype != StreamTokenizer.TT_EOL &&
  141.             st.ttype != StreamTokenizer.TT_EOF)
  142.             st.nextToken();
  143.         }
  144.     is.close();
  145.     if (st.ttype != StreamTokenizer.TT_EOF)
  146.         throw new Exception(st.toString());
  147.     }
  148.  
  149.     /** Add a vertex to this model */
  150.     int addVert(String name, float x, float y, float z) {
  151.     int i = nvert;
  152.     if (i >= maxvert)
  153.         if (vert == null) {
  154.         maxvert = 100;
  155.         vert = new float[maxvert * 3];
  156.         atoms = new Atom[maxvert];
  157.         } else {
  158.         maxvert *= 2;
  159.         float nv[] = new float[maxvert * 3];
  160.         System.arraycopy(vert, 0, nv, 0, vert.length);
  161.         vert = nv;
  162.         Atom na[] = new Atom[maxvert];
  163.         System.arraycopy(atoms, 0, na, 0, atoms.length);
  164.         atoms = na;
  165.         }
  166.     Atom a = (Atom) atomTable.get(name.toLowerCase());
  167.     if (a == null) a = defaultAtom;
  168.     atoms[i] = a;
  169.     i *= 3;
  170.     vert[i] = x;
  171.     vert[i + 1] = y;
  172.     vert[i + 2] = z;
  173.     return nvert++;
  174.     }
  175.  
  176.     /** Transform all the points in this model */
  177.     void transform() {
  178.     if (transformed || nvert <= 0)
  179.         return;
  180.     if (tvert == null || tvert.length < nvert * 3)
  181.         tvert = new int[nvert * 3];
  182.     mat.transform(vert, tvert, nvert);
  183.     transformed = true;
  184.     }
  185.  
  186.  
  187.     /** Paint this model to a graphics context.  It uses the matrix associated
  188.     with this model to map from model space to screen space.
  189.     The next version of the browser should have double buffering,
  190.     which will make this *much* nicer */
  191.     void paint(Graphics g, Component parent) {
  192.     if (vert == null || nvert <= 0)
  193.         return;
  194.     transform();
  195.     int v[] = tvert;
  196.     int zs[] = ZsortMap;
  197.     if (zs == null) {
  198.         ZsortMap = zs = new int[nvert];
  199.         for (int i = nvert; --i >= 0;)
  200.         zs[i] = i * 3;
  201.     }
  202.  
  203.     /*
  204.      * I use a bubble sort since from one iteration to the next, the sort
  205.      * order is pretty stable, so I just use what I had last time as a
  206.      * "guess" of the sorted order.  With luck, this reduces O(N log N)
  207.      * to O(N)
  208.      */
  209.  
  210.     for (int i = nvert - 1; --i >= 0;) {
  211.         boolean flipped = false;
  212.         for (int j = 0; j <= i; j++) {
  213.         int a = zs[j];
  214.         int b = zs[j + 1];
  215.         if (v[a + 2] > v[b + 2]) {
  216.             zs[j + 1] = a;
  217.             zs[j] = b;
  218.             flipped = true;
  219.         }
  220.         }
  221.         if (!flipped)
  222.         break;
  223.     }
  224.  
  225.     int lg = 0;
  226.     int lim = nvert;
  227.     Atom ls[] = atoms;
  228.     if (lim <= 0 || nvert <= 0)
  229.         return;
  230.     for (int i = 0; i < lim; i++) {
  231.         int j = zs[i];
  232.         int grey = v[j + 2];
  233.         if (grey < 0)
  234.         grey = 0;
  235.         if (grey > 15)
  236.         grey = 15;
  237.         // g.drawString(names[i], v[j], v[j+1]);
  238.         atoms[j/3].paint(g, v[j], v[j + 1], grey, parent);
  239.         // g.drawImage(iBall, v[j] - (iBall.width >> 1), v[j + 1] -
  240.         // (iBall.height >> 1));
  241.     }
  242.     }
  243.  
  244.     /** Find the bounding box of this model */
  245.     void findBB() {
  246.     if (nvert <= 0)
  247.         return;
  248.     float v[] = vert;
  249.     float xmin = v[0], xmax = xmin;
  250.     float ymin = v[1], ymax = ymin;
  251.     float zmin = v[2], zmax = zmin;
  252.     for (int i = nvert * 3; (i -= 3) > 0;) {
  253.         float x = v[i];
  254.         if (x < xmin)
  255.         xmin = x;
  256.         if (x > xmax)
  257.         xmax = x;
  258.         float y = v[i + 1];
  259.         if (y < ymin)
  260.         ymin = y;
  261.         if (y > ymax)
  262.         ymax = y;
  263.         float z = v[i + 2];
  264.         if (z < zmin)
  265.         zmin = z;
  266.         if (z > zmax)
  267.         zmax = z;
  268.     }
  269.     this.xmax = xmax;
  270.     this.xmin = xmin;
  271.     this.ymax = ymax;
  272.     this.ymin = ymin;
  273.     this.zmax = zmax;
  274.     this.zmin = zmin;
  275.     }
  276. }
  277.  
  278. // XYZCanvas
  279. // Where the actual drawing takes place
  280. class XYZCanvas extends Canvas {
  281.     XYZChemModel md;
  282.     float xfac;
  283.     int prevx, prevy;
  284.     float xtheta, ytheta;
  285.     float scalefudge = 1;
  286.     Matrix3D amat = new Matrix3D(), tmat = new Matrix3D();
  287.     Image dbuf;
  288.  
  289.     // loadmodel
  290.     // Read a model to use from the given stream
  291.     boolean loadmodel(InputStream is)
  292.     {
  293.     try {
  294.         XYZChemModel m = new XYZChemModel (is);
  295.         md = m;
  296.         m.findBB();
  297.         dbuf = null;    // force rescale
  298.         }
  299.     catch(Exception e)
  300.         return false;
  301.     paint(getGraphics());
  302.     return true;
  303.     }
  304.  
  305.     public boolean mouseDown(Event e, int x, int y)
  306.     {
  307.     prevx = x;
  308.     prevy = y;
  309.     return true;
  310.     }
  311.  
  312.     public boolean mouseDrag(Event e, int x, int y)
  313.     {
  314.     tmat.unit();
  315.     float xtheta = (prevy - y) * (360.0f / size().width);
  316.     float ytheta = (x - prevx) * (360.0f / size().height);
  317.     tmat.xrot(xtheta);
  318.     tmat.yrot(ytheta);
  319.     amat.mult(tmat);
  320.     repaint();
  321.     prevx = x;
  322.     prevy = y;
  323.     return true;
  324.     }
  325.  
  326.     public void update(Graphics g)
  327.     {
  328.     paint(g);
  329.     }
  330.  
  331.     public void paint(Graphics fg)
  332.     {
  333.     if (fg == null)
  334.         return;        // not visible yet
  335.     if (dbuf == null || dbuf.getWidth(this) != size().width ||
  336.                 dbuf.getHeight(this) != size().height) {
  337.         // we have been resized
  338.         dbuf = createImage(size().width, size().height);
  339.         float xw = md.xmax - md.xmin;
  340.         float yw = md.ymax - md.ymin;
  341.         float zw = md.zmax - md.zmin;
  342.         if (yw > xw)
  343.         xw = yw;
  344.         if (zw > xw)
  345.         xw = zw;
  346.         float f1 = size().width / xw;
  347.         float f2 = size().height / xw;
  348.         xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge;
  349.         }
  350.     Graphics g = dbuf.getGraphics();
  351.     g.setColor(Color.lightGray);
  352.     g.fillRect(0, 0, size().width, size().height);
  353.     if (md != null) {
  354.         md.mat.unit();
  355.         md.mat.translate(-(md.xmin + md.xmax) / 2,
  356.                  -(md.ymin + md.ymax) / 2,
  357.                  -(md.zmin + md.zmax) / 2);
  358.         md.mat.mult(amat);
  359.         md.mat.scale(xfac, -xfac, 16 * xfac / size().width);
  360.         md.mat.translate(size().width / 2, size().height / 2, 8);
  361.         md.transformed = false;
  362.         md.paint(g, this);
  363.         }
  364.     fg.drawImage(dbuf, 0, 0, this);
  365.     }
  366. }
  367.  
  368. class Atom {
  369.     private static byte[] data;
  370.     private final static int R = 40;
  371.     private final static int hx = 15;
  372.     private final static int hy = 15;
  373.     private final static int bgGrey = 192;
  374.     private final static int nBalls = 16;
  375.     private static int maxr;
  376.  
  377.     private int Rl;
  378.     private int Gl;
  379.     private int Bl;
  380.     private Image balls[];
  381.  
  382.     static {
  383.     data = new byte[R * 2 * R * 2];
  384.     int mr = 0;
  385.     for (int Y = 2 * R; --Y >= 0;) {
  386.         int x0 = (int) (Math.sqrt(R * R - (Y - R) * (Y - R)) + 0.5);
  387.         int p = Y * (R * 2) + R - x0;
  388.         for (int X = -x0; X < x0; X++) {
  389.         int x = X + hx;
  390.         int y = Y - R + hy;
  391.         int r = (int) (Math.sqrt(x * x + y * y) + 0.5);
  392.         if (r > mr)
  393.             mr = r;
  394.         data[p++] = r <= 0 ? 1 : (byte) r;
  395.         }
  396.     }
  397.     maxr = mr;
  398.     }
  399.     Atom(int Rl, int Gl, int Bl) {
  400.     this.Rl = Rl;
  401.     this.Gl = Gl;
  402.     this.Bl = Bl;
  403.     }
  404.     private final int blend(int fg, int bg, float fgfactor) {
  405.     return (int) (bg + (fg - bg) * fgfactor);
  406.     }
  407.     private void Setup(Component parent) {
  408.     balls = new Image[nBalls];
  409.     byte red[] = new byte[256];
  410.     red[0] = (byte) bgGrey;
  411.     byte green[] = new byte[256];
  412.     green[0] = (byte) bgGrey;
  413.     byte blue[] = new byte[256];
  414.     blue[0] = (byte) bgGrey;
  415.     for (int r = 0; r < nBalls; r++) {
  416.         float b = (float) (r+1) / nBalls;
  417.         for (int i = maxr; i >= 1; --i) {
  418.         float d = (float) i / maxr;
  419.         red[i] = (byte) blend(blend(Rl, 255, d), bgGrey, b);
  420.         green[i] = (byte) blend(blend(Gl, 255, d), bgGrey, b);
  421.         blue[i] = (byte) blend(blend(Bl, 255, d), bgGrey, b);
  422.         }
  423.         IndexColorModel model = new IndexColorModel(8, maxr + 1,
  424.                             red, green, blue, 0);
  425.         balls[r] = parent.createImage(
  426.         new MemoryImageSource(R*2, R*2, model, data, 0, R*2));
  427.     }
  428.     }
  429.     void paint(Graphics gc, int x, int y, int r, Component parent) {
  430.     Image ba[] = balls;
  431.     if (ba == null) {
  432.         Setup(parent);
  433.         ba = balls;
  434.     }
  435.     Image i = ba[r];
  436.     int size = 10 + r;
  437.     gc.drawImage(i, x - (size >> 1), y - (size >> 1), size, size, parent);
  438.     }
  439. }
  440.