src/demo/share/applets/MoleculeViewer/XYZApp.java
changeset 50831 59c6972e39fa
parent 50830 5500595d8ebf
child 50832 e069b9e49ca7
equal deleted inserted replaced
50830:5500595d8ebf 50831:59c6972e39fa
     1 /*
       
     2  * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     8  *   - Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer.
       
    10  *
       
    11  *   - Redistributions in binary form must reproduce the above copyright
       
    12  *     notice, this list of conditions and the following disclaimer in the
       
    13  *     documentation and/or other materials provided with the distribution.
       
    14  *
       
    15  *   - Neither the name of Oracle nor the names of its
       
    16  *     contributors may be used to endorse or promote products derived
       
    17  *     from this software without specific prior written permission.
       
    18  *
       
    19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
       
    20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
       
    21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
       
    23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
       
    27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
       
    28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
       
    29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    30  */
       
    31 
       
    32 /*
       
    33  * This source code is provided to illustrate the usage of a given feature
       
    34  * or technique and has been deliberately simplified. Additional steps
       
    35  * required for a production-quality application, such as security checks,
       
    36  * input validation and proper error handling, might not be present in
       
    37  * this sample code.
       
    38  */
       
    39 
       
    40 
       
    41 
       
    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;
       
    49 import java.net.URL;
       
    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;
       
    58 import java.util.Map;
       
    59 import java.util.logging.Level;
       
    60 import java.util.logging.Logger;
       
    61 
       
    62 
       
    63 /*
       
    64  * A set of classes to parse, represent and display Chemical compounds in
       
    65  * .xyz format (see http://chem.leeds.ac.uk/Project/MIME.html)
       
    66  */
       
    67 /** The representation of a Chemical .xyz model */
       
    68 final class XYZChemModel {
       
    69 
       
    70     float vert[];
       
    71     Atom atoms[];
       
    72     int tvert[];
       
    73     int ZsortMap[];
       
    74     int nvert, maxvert;
       
    75     static final Map<String, Atom> atomTable = new HashMap<String, Atom>();
       
    76     static Atom defaultAtom;
       
    77 
       
    78     static {
       
    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);
       
    87     }
       
    88     boolean transformed;
       
    89     Matrix3D mat;
       
    90     float xmin, xmax, ymin, ymax, zmin, zmax;
       
    91 
       
    92     XYZChemModel() {
       
    93         mat = new Matrix3D();
       
    94         mat.xrot(20);
       
    95         mat.yrot(30);
       
    96     }
       
    97 
       
    98     /** Create a Chemical model by parsing an input stream */
       
    99     XYZChemModel(InputStream is) throws Exception {
       
   100         this();
       
   101         StreamTokenizer st = new StreamTokenizer(
       
   102                 new BufferedReader(new InputStreamReader(is, "UTF-8")));
       
   103         st.eolIsSignificant(true);
       
   104         st.commentChar('#');
       
   105 
       
   106         try {
       
   107             scan:
       
   108             while (true) {
       
   109                 switch (st.nextToken()) {
       
   110                     case StreamTokenizer.TT_EOF:
       
   111                         break scan;
       
   112                     default:
       
   113                         break;
       
   114                     case StreamTokenizer.TT_WORD:
       
   115                         String name = st.sval;
       
   116                         double x = 0,
       
   117                          y = 0,
       
   118                          z = 0;
       
   119                         if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
       
   120                             x = st.nval;
       
   121                             if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
       
   122                                 y = st.nval;
       
   123                                 if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
       
   124                                     z = st.nval;
       
   125                                 }
       
   126                             }
       
   127                         }
       
   128                         addVert(name, (float) x, (float) y, (float) z);
       
   129                         while (st.ttype != StreamTokenizer.TT_EOL
       
   130                                 && st.ttype != StreamTokenizer.TT_EOF) {
       
   131                             st.nextToken();
       
   132                         }
       
   133 
       
   134                 }   // end Switch
       
   135 
       
   136             }  // end while
       
   137 
       
   138             is.close();
       
   139 
       
   140         } // end Try
       
   141         catch (IOException e) {
       
   142         }
       
   143 
       
   144         if (st.ttype != StreamTokenizer.TT_EOF) {
       
   145             throw new Exception(st.toString());
       
   146         }
       
   147 
       
   148     }  // end XYZChemModel()
       
   149 
       
   150     /** Add a vertex to this model */
       
   151     int addVert(String name, float x, float y, float z) {
       
   152         int i = nvert;
       
   153         if (i >= maxvert) {
       
   154             if (vert == null) {
       
   155                 maxvert = 100;
       
   156                 vert = new float[maxvert * 3];
       
   157                 atoms = new Atom[maxvert];
       
   158             } else {
       
   159                 maxvert *= 2;
       
   160                 float nv[] = new float[maxvert * 3];
       
   161                 System.arraycopy(vert, 0, nv, 0, vert.length);
       
   162                 vert = nv;
       
   163                 Atom na[] = new Atom[maxvert];
       
   164                 System.arraycopy(atoms, 0, na, 0, atoms.length);
       
   165                 atoms = na;
       
   166             }
       
   167         }
       
   168         Atom a = atomTable.get(name.toLowerCase());
       
   169         if (a == null) {
       
   170             a = defaultAtom;
       
   171         }
       
   172         atoms[i] = a;
       
   173         i *= 3;
       
   174         vert[i] = x;
       
   175         vert[i + 1] = y;
       
   176         vert[i + 2] = z;
       
   177         return nvert++;
       
   178     }
       
   179 
       
   180     /** Transform all the points in this model */
       
   181     void transform() {
       
   182         if (transformed || nvert <= 0) {
       
   183             return;
       
   184         }
       
   185         if (tvert == null || tvert.length < nvert * 3) {
       
   186             tvert = new int[nvert * 3];
       
   187         }
       
   188         mat.transform(vert, tvert, nvert);
       
   189         transformed = true;
       
   190     }
       
   191 
       
   192     /** Paint this model to a graphics context.  It uses the matrix associated
       
   193     with this model to map from model space to screen space.
       
   194     The next version of the browser should have double buffering,
       
   195     which will make this *much* nicer */
       
   196     void paint(Graphics g) {
       
   197         if (vert == null || nvert <= 0) {
       
   198             return;
       
   199         }
       
   200         transform();
       
   201         int v[] = tvert;
       
   202         int zs[] = ZsortMap;
       
   203         if (zs == null) {
       
   204             ZsortMap = zs = new int[nvert];
       
   205             for (int i = nvert; --i >= 0;) {
       
   206                 zs[i] = i * 3;
       
   207             }
       
   208         }
       
   209 
       
   210         /*
       
   211          * I use a bubble sort since from one iteration to the next, the sort
       
   212          * order is pretty stable, so I just use what I had last time as a
       
   213          * "guess" of the sorted order.  With luck, this reduces O(N log N)
       
   214          * to O(N)
       
   215          */
       
   216 
       
   217         for (int i = nvert - 1; --i >= 0;) {
       
   218             boolean flipped = false;
       
   219             for (int j = 0; j <= i; j++) {
       
   220                 int a = zs[j];
       
   221                 int b = zs[j + 1];
       
   222                 if (v[a + 2] > v[b + 2]) {
       
   223                     zs[j + 1] = a;
       
   224                     zs[j] = b;
       
   225                     flipped = true;
       
   226                 }
       
   227             }
       
   228             if (!flipped) {
       
   229                 break;
       
   230             }
       
   231         }
       
   232 
       
   233         int lim = nvert;
       
   234         if (lim <= 0 || nvert <= 0) {
       
   235             return;
       
   236         }
       
   237         for (int i = 0; i < lim; i++) {
       
   238             int j = zs[i];
       
   239             int grey = v[j + 2];
       
   240             if (grey < 0) {
       
   241                 grey = 0;
       
   242             }
       
   243             if (grey > 15) {
       
   244                 grey = 15;
       
   245             }
       
   246             // g.drawString(names[i], v[j], v[j+1]);
       
   247             atoms[j / 3].paint(g, v[j], v[j + 1], grey);
       
   248             // g.drawImage(iBall, v[j] - (iBall.width >> 1), v[j + 1] -
       
   249             // (iBall.height >> 1));
       
   250         }
       
   251     }
       
   252 
       
   253     /** Find the bounding box of this model */
       
   254     void findBB() {
       
   255         if (nvert <= 0) {
       
   256             return;
       
   257         }
       
   258         float v[] = vert;
       
   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;) {
       
   263             float x = v[i];
       
   264             if (x < _xmin) {
       
   265                 _xmin = x;
       
   266             }
       
   267             if (x > _xmax) {
       
   268                 _xmax = x;
       
   269             }
       
   270             float y = v[i + 1];
       
   271             if (y < _ymin) {
       
   272                 _ymin = y;
       
   273             }
       
   274             if (y > _ymax) {
       
   275                 _ymax = y;
       
   276             }
       
   277             float z = v[i + 2];
       
   278             if (z < _zmin) {
       
   279                 _zmin = z;
       
   280             }
       
   281             if (z > _zmax) {
       
   282                 _zmax = z;
       
   283             }
       
   284         }
       
   285         this.xmax = _xmax;
       
   286         this.xmin = _xmin;
       
   287         this.ymax = _ymax;
       
   288         this.ymin = _ymin;
       
   289         this.zmax = _zmax;
       
   290         this.zmin = _zmin;
       
   291     }
       
   292 }
       
   293 
       
   294 
       
   295 /** An applet to put a Chemical model into a page */
       
   296 @SuppressWarnings("serial")
       
   297 public class XYZApp extends Applet implements Runnable, MouseListener,
       
   298         MouseMotionListener {
       
   299 
       
   300     XYZChemModel md;
       
   301     boolean painted = true;
       
   302     float xfac;
       
   303     int prevx, prevy;
       
   304     float scalefudge = 1;
       
   305     Matrix3D amat = new Matrix3D(), tmat = new Matrix3D();
       
   306     String mdname = null;
       
   307     String message = null;
       
   308     Image backBuffer;
       
   309     Graphics backGC;
       
   310     Dimension backSize;
       
   311 
       
   312     private synchronized void newBackBuffer() {
       
   313         backBuffer = createImage(getSize().width, getSize().height);
       
   314         if (backGC != null) {
       
   315             backGC.dispose();
       
   316         }
       
   317         backGC = backBuffer.getGraphics();
       
   318         backSize = getSize();
       
   319     }
       
   320 
       
   321     @Override
       
   322     public void init() {
       
   323         mdname = getParameter("model");
       
   324         try {
       
   325             scalefudge = Float.valueOf(getParameter("scale")).floatValue();
       
   326         } catch (Exception ignored) {
       
   327         }
       
   328         amat.yrot(20);
       
   329         amat.xrot(20);
       
   330         if (mdname == null) {
       
   331             mdname = "model.obj";
       
   332         }
       
   333         resize(getSize().width <= 20 ? 400 : getSize().width,
       
   334                 getSize().height <= 20 ? 400 : getSize().height);
       
   335         newBackBuffer();
       
   336         addMouseListener(this);
       
   337         addMouseMotionListener(this);
       
   338     }
       
   339 
       
   340     @Override
       
   341     public void destroy() {
       
   342         removeMouseListener(this);
       
   343         removeMouseMotionListener(this);
       
   344     }
       
   345 
       
   346     @Override
       
   347     public void run() {
       
   348         InputStream is = null;
       
   349         try {
       
   350             Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
       
   351             is = getClass().getResourceAsStream(mdname);
       
   352             XYZChemModel m = new XYZChemModel(is);
       
   353             Atom.setApplet(this);
       
   354             md = m;
       
   355             m.findBB();
       
   356             float xw = m.xmax - m.xmin;
       
   357             float yw = m.ymax - m.ymin;
       
   358             float zw = m.zmax - m.zmin;
       
   359             if (yw > xw) {
       
   360                 xw = yw;
       
   361             }
       
   362             if (zw > xw) {
       
   363                 xw = zw;
       
   364             }
       
   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);
       
   370             md = null;
       
   371             message = e.toString();
       
   372         }
       
   373         try {
       
   374             if (is != null) {
       
   375                 is.close();
       
   376             }
       
   377         } catch (Exception ignored) {
       
   378         }
       
   379         repaint();
       
   380     }
       
   381 
       
   382     @Override
       
   383     public void start() {
       
   384         if (md == null && message == null) {
       
   385             new Thread(this).start();
       
   386         }
       
   387     }
       
   388 
       
   389     @Override
       
   390     public void stop() {
       
   391     }
       
   392     /* event handling */
       
   393 
       
   394     @Override
       
   395     public void mouseClicked(MouseEvent e) {
       
   396     }
       
   397 
       
   398     @Override
       
   399     public void mousePressed(MouseEvent e) {
       
   400         prevx = e.getX();
       
   401         prevy = e.getY();
       
   402         e.consume();
       
   403     }
       
   404 
       
   405     @Override
       
   406     public void mouseReleased(MouseEvent e) {
       
   407     }
       
   408 
       
   409     @Override
       
   410     public void mouseEntered(MouseEvent e) {
       
   411     }
       
   412 
       
   413     @Override
       
   414     public void mouseExited(MouseEvent e) {
       
   415     }
       
   416 
       
   417     @Override
       
   418     public void mouseDragged(MouseEvent e) {
       
   419         int x = e.getX();
       
   420         int y = e.getY();
       
   421         tmat.unit();
       
   422         float xtheta = (prevy - y) * (360.0f / getSize().width);
       
   423         float ytheta = (x - prevx) * (360.0f / getSize().height);
       
   424         tmat.xrot(xtheta);
       
   425         tmat.yrot(ytheta);
       
   426         amat.mult(tmat);
       
   427         if (painted) {
       
   428             painted = false;
       
   429             repaint();
       
   430         }
       
   431         prevx = x;
       
   432         prevy = y;
       
   433         e.consume();
       
   434     }
       
   435 
       
   436     @Override
       
   437     public void mouseMoved(MouseEvent e) {
       
   438     }
       
   439 
       
   440     @Override
       
   441     public void update(Graphics g) {
       
   442         if (backBuffer == null) {
       
   443             g.clearRect(0, 0, getSize().width, getSize().height);
       
   444         }
       
   445         paint(g);
       
   446     }
       
   447 
       
   448     @Override
       
   449     public void paint(Graphics g) {
       
   450         if (md != null) {
       
   451             md.mat.unit();
       
   452             md.mat.translate(-(md.xmin + md.xmax) / 2,
       
   453                     -(md.ymin + md.ymax) / 2,
       
   454                     -(md.zmin + md.zmax) / 2);
       
   455             md.mat.mult(amat);
       
   456             // md.mat.scale(xfac, -xfac, 8 * xfac / getSize().width);
       
   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())) {
       
   462                     newBackBuffer();
       
   463                 }
       
   464                 backGC.setColor(getBackground());
       
   465                 backGC.fillRect(0, 0, getSize().width, getSize().height);
       
   466                 md.paint(backGC);
       
   467                 g.drawImage(backBuffer, 0, 0, this);
       
   468             } else {
       
   469                 md.paint(g);
       
   470             }
       
   471             setPainted();
       
   472         } else if (message != null) {
       
   473             g.drawString("Error in model:", 3, 20);
       
   474             g.drawString(message, 10, 40);
       
   475         }
       
   476     }
       
   477 
       
   478     private synchronized void setPainted() {
       
   479         painted = true;
       
   480         notifyAll();
       
   481     }
       
   482 
       
   483     @Override
       
   484     public String getAppletInfo() {
       
   485         return "Title: XYZApp \nAuthor: James Gosling \nAn applet to put"
       
   486                 + " a Chemical model into a page.";
       
   487     }
       
   488 
       
   489     @Override
       
   490     public String[][] getParameterInfo() {
       
   491         String[][] info = {
       
   492             { "model", "path string", "The path to the model to be displayed"
       
   493                 + " in .xyz format "
       
   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)." }
       
   497         };
       
   498         return info;
       
   499     }
       
   500 }   // end class XYZApp
       
   501 
       
   502 
       
   503 class Atom {
       
   504 
       
   505     private static Applet applet;
       
   506     private static byte[] data;
       
   507     private static final int R = 40;
       
   508     private static final int hx = 15;
       
   509     private static final int hy = 15;
       
   510     private static final int bgGrey = 192;
       
   511     private static final int nBalls = 16;
       
   512     private static int maxr;
       
   513     private int Rl;
       
   514     private int Gl;
       
   515     private int Bl;
       
   516     private Image balls[];
       
   517 
       
   518     static {
       
   519         data = new byte[R * 2 * R * 2];
       
   520         int mr = 0;
       
   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++) {
       
   525                 int x = X + hx;
       
   526                 int y = Y - R + hy;
       
   527                 int r = (int) (Math.sqrt(x * x + y * y) + 0.5);
       
   528                 if (r > mr) {
       
   529                     mr = r;
       
   530                 }
       
   531                 data[p++] = r <= 0 ? 1 : (byte) r;
       
   532             }
       
   533         }
       
   534         maxr = mr;
       
   535     }
       
   536 
       
   537     static void setApplet(Applet app) {
       
   538         applet = app;
       
   539     }
       
   540 
       
   541     Atom(int Rl, int Gl, int Bl) {
       
   542         this.Rl = Rl;
       
   543         this.Gl = Gl;
       
   544         this.Bl = Bl;
       
   545     }
       
   546 
       
   547     private int blend(int fg, int bg, float fgfactor) {
       
   548         return (int) (bg + (fg - bg) * fgfactor);
       
   549     }
       
   550 
       
   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);
       
   566             }
       
   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));
       
   571         }
       
   572     }
       
   573 
       
   574     void paint(Graphics gc, int x, int y, int r) {
       
   575         Image ba[] = balls;
       
   576         if (ba == null) {
       
   577             Setup();
       
   578             ba = balls;
       
   579         }
       
   580         Image i = ba[r];
       
   581         int size = 10 + r;
       
   582         gc.drawImage(i, x - (size >> 1), y - (size >> 1), size, size, applet);
       
   583     }
       
   584 }