KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > XYZApp


1 /*
2  * @(#)XYZApp.java 1.19 06/02/22
3  *
4  * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * -Redistribution of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  *
12  * -Redistribution in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * Neither the name of Sun Microsystems, Inc. or the names of contributors may
17  * be used to endorse or promote products derived from this software without
18  * specific prior written permission.
19  *
20  * This software is provided "AS IS," without a warranty of any kind. ALL
21  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
22  * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23  * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
24  * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
25  * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
26  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
27  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
28  * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
29  * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  *
32  * You acknowledge that this software is not designed, licensed or intended
33  * for use in the design, construction, operation or maintenance of any
34  * nuclear facility.
35  */

36
37 /*
38  * @(#)XYZApp.java 1.19 06/02/22
39  */

40
41 /*
42  * A set of classes to parse, represent and display Chemical compounds in
43  * .xyz format (see http://chem.leeds.ac.uk/Project/MIME.html)
44  */

45
46 import java.applet.Applet JavaDoc;
47 import java.awt.Image JavaDoc;
48 import java.awt.Event JavaDoc;
49 import java.awt.Graphics JavaDoc;
50 import java.awt.Dimension JavaDoc;
51 import java.io.*;
52 import java.net.URL JavaDoc;
53 import java.util.Hashtable JavaDoc;
54 import java.awt.image.IndexColorModel JavaDoc;
55 import java.awt.image.ColorModel JavaDoc;
56 import java.awt.image.MemoryImageSource JavaDoc;
57 import java.awt.event.*;
58
59 /** The representation of a Chemical .xyz model */
60 class XYZChemModel {
61     float vert[];
62     Atom atoms[];
63     int tvert[];
64     int ZsortMap[];
65     int nvert, maxvert;
66
67     static Hashtable JavaDoc atomTable = new Hashtable JavaDoc();
68     static Atom defaultAtom;
69     static {
70     atomTable.put("c", new Atom(0, 0, 0));
71     atomTable.put("h", new Atom(210, 210, 210));
72     atomTable.put("n", new Atom(0, 0, 255));
73     atomTable.put("o", new Atom(255, 0, 0));
74     atomTable.put("p", new Atom(255, 0, 255));
75     atomTable.put("s", new Atom(255, 255, 0));
76     atomTable.put("hn", new Atom(150, 255, 150)); /* !!*/
77     defaultAtom = new Atom(255, 100, 200);
78     }
79
80     boolean transformed;
81     Matrix3D mat;
82
83     float xmin, xmax, ymin, ymax, zmin, zmax;
84
85
86     XYZChemModel () {
87     mat = new Matrix3D();
88     mat.xrot(20);
89     mat.yrot(30);
90     }
91
92
93     /** Create a Cehmical model by parsing an input stream */
94     XYZChemModel (InputStream is) throws Exception JavaDoc
95     {
96        this();
97        StreamTokenizer st = new StreamTokenizer(
98                new BufferedReader(new InputStreamReader(is, "UTF-8")));
99        st.eolIsSignificant(true);
100        st.commentChar('#');
101        int slot = 0;
102
103        try
104        {
105 scan:
106           while (true)
107           {
108              switch ( st.nextToken() )
109              {
110                 case StreamTokenizer.TT_EOF:
111                    break scan;
112                 default:
113                    break;
114                 case StreamTokenizer.TT_WORD:
115                    String JavaDoc name = st.sval;
116                    double x = 0, y = 0, z = 0;
117                    if (st.nextToken() == StreamTokenizer.TT_NUMBER)
118                    {
119                       x = st.nval;
120                       if (st.nextToken() == StreamTokenizer.TT_NUMBER)
121                       {
122                          y = st.nval;
123                          if (st.nextToken() == StreamTokenizer.TT_NUMBER)
124                             z = st.nval;
125                       }
126                    }
127                    addVert(name, (float) x, (float) y, (float) z);
128                    while( st.ttype != StreamTokenizer.TT_EOL &&
129                           st.ttype != StreamTokenizer.TT_EOF )
130                       st.nextToken();
131
132              } // end Switch
133

134           } // end while
135

136           is.close();
137
138        } // end Try
139
catch( IOException e) {}
140
141        if (st.ttype != StreamTokenizer.TT_EOF)
142           throw new Exception JavaDoc(st.toString());
143
144     } // end XYZChemModel()
145

146     /** Add a vertex to this model */
147     int addVert(String JavaDoc name, float x, float y, float z) {
148     int i = nvert;
149     if (i >= maxvert)
150         if (vert == null) {
151         maxvert = 100;
152         vert = new float[maxvert * 3];
153         atoms = new Atom[maxvert];
154         } else {
155         maxvert *= 2;
156         float nv[] = new float[maxvert * 3];
157         System.arraycopy(vert, 0, nv, 0, vert.length);
158         vert = nv;
159         Atom na[] = new Atom[maxvert];
160         System.arraycopy(atoms, 0, na, 0, atoms.length);
161         atoms = na;
162         }
163     Atom a = (Atom) atomTable.get(name.toLowerCase());
164     if (a == null) a = defaultAtom;
165     atoms[i] = a;
166     i *= 3;
167     vert[i] = x;
168     vert[i + 1] = y;
169     vert[i + 2] = z;
170     return nvert++;
171     }
172
173     /** Transform all the points in this model */
174     void transform() {
175     if (transformed || nvert <= 0)
176         return;
177     if (tvert == null || tvert.length < nvert * 3)
178         tvert = new int[nvert * 3];
179     mat.transform(vert, tvert, nvert);
180     transformed = true;
181     }
182
183
184     /** Paint this model to a graphics context. It uses the matrix associated
185     with this model to map from model space to screen space.
186     The next version of the browser should have double buffering,
187     which will make this *much* nicer */

188     void paint(Graphics JavaDoc g) {
189     if (vert == null || nvert <= 0)
190         return;
191     transform();
192     int v[] = tvert;
193     int zs[] = ZsortMap;
194     if (zs == null) {
195         ZsortMap = zs = new int[nvert];
196         for (int i = nvert; --i >= 0;)
197         zs[i] = i * 3;
198     }
199
200     /*
201      * I use a bubble sort since from one iteration to the next, the sort
202      * order is pretty stable, so I just use what I had last time as a
203      * "guess" of the sorted order. With luck, this reduces O(N log N)
204      * to O(N)
205      */

206
207     for (int i = nvert - 1; --i >= 0;) {
208         boolean flipped = false;
209         for (int j = 0; j <= i; j++) {
210         int a = zs[j];
211         int b = zs[j + 1];
212         if (v[a + 2] > v[b + 2]) {
213             zs[j + 1] = a;
214             zs[j] = b;
215             flipped = true;
216         }
217         }
218         if (!flipped)
219         break;
220     }
221
222     int lg = 0;
223     int lim = nvert;
224     Atom ls[] = atoms;
225     if (lim <= 0 || nvert <= 0)
226         return;
227     for (int i = 0; i < lim; i++) {
228         int j = zs[i];
229         int grey = v[j + 2];
230         if (grey < 0)
231         grey = 0;
232         if (grey > 15)
233         grey = 15;
234         // g.drawString(names[i], v[j], v[j+1]);
235
atoms[j/3].paint(g, v[j], v[j + 1], grey);
236         // g.drawImage(iBall, v[j] - (iBall.width >> 1), v[j + 1] -
237
// (iBall.height >> 1));
238
}
239     }
240
241     /** Find the bounding box of this model */
242     void findBB() {
243     if (nvert <= 0)
244         return;
245     float v[] = vert;
246     float xmin = v[0], xmax = xmin;
247     float ymin = v[1], ymax = ymin;
248     float zmin = v[2], zmax = zmin;
249     for (int i = nvert * 3; (i -= 3) > 0;) {
250         float x = v[i];
251         if (x < xmin)
252         xmin = x;
253         if (x > xmax)
254         xmax = x;
255         float y = v[i + 1];
256         if (y < ymin)
257         ymin = y;
258         if (y > ymax)
259         ymax = y;
260         float z = v[i + 2];
261         if (z < zmin)
262         zmin = z;
263         if (z > zmax)
264         zmax = z;
265     }
266     this.xmax = xmax;
267     this.xmin = xmin;
268     this.ymax = ymax;
269     this.ymin = ymin;
270     this.zmax = zmax;
271     this.zmin = zmin;
272     }
273 }
274
275 /** An applet to put a Chemical model into a page */
276 public class XYZApp
277     extends Applet JavaDoc
278     implements Runnable JavaDoc, MouseListener, MouseMotionListener {
279     XYZChemModel md;
280     boolean painted = true;
281     float xfac;
282     int prevx, prevy;
283     float xtheta, ytheta;
284     float scalefudge = 1;
285     Matrix3D amat = new Matrix3D(), tmat = new Matrix3D();
286     String JavaDoc mdname = null;
287     String JavaDoc message = null;
288     Image JavaDoc backBuffer;
289     Graphics JavaDoc backGC;
290     Dimension JavaDoc backSize;
291
292
293     private synchronized void newBackBuffer() {
294     backBuffer = createImage(getSize().width, getSize().height);
295     if (backGC != null) {
296         backGC.dispose();
297     }
298     backGC = backBuffer.getGraphics();
299     backSize = getSize();
300     }
301
302     public void init() {
303     mdname = getParameter("model");
304     try {
305         scalefudge = Float.valueOf(getParameter("scale")).floatValue();
306     } catch(Exception JavaDoc e) {
307     };
308     amat.yrot(20);
309     amat.xrot(20);
310     if (mdname == null)
311         mdname = "model.obj";
312     resize(getSize().width <= 20 ? 400 : getSize().width,
313            getSize().height <= 20 ? 400 : getSize().height);
314     newBackBuffer();
315     addMouseListener(this);
316     addMouseMotionListener(this);
317     }
318
319     public void destroy() {
320         removeMouseListener(this);
321         removeMouseMotionListener(this);
322     }
323
324     public void run() {
325     InputStream is = null;
326     try {
327         Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
328         is = new URL JavaDoc(getDocumentBase(), mdname).openStream();
329         XYZChemModel m = new XYZChemModel (is);
330         Atom.setApplet(this);
331         md = m;
332         m.findBB();
333         float xw = m.xmax - m.xmin;
334         float yw = m.ymax - m.ymin;
335         float zw = m.zmax - m.zmin;
336         if (yw > xw)
337         xw = yw;
338         if (zw > xw)
339         xw = zw;
340         float f1 = getSize().width / xw;
341         float f2 = getSize().height / xw;
342         xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge;
343     } catch(Exception JavaDoc e) {
344         e.printStackTrace();
345         md = null;
346         message = e.toString();
347     }
348     try {
349         if (is != null)
350         is.close();
351     } catch(Exception JavaDoc e) {
352     }
353     repaint();
354     }
355     public void start() {
356     if (md == null && message == null)
357         new Thread JavaDoc(this).start();
358     }
359     public void stop() {
360     }
361       /* event handling */
362   public void mouseClicked(MouseEvent e) {
363   }
364   public void mousePressed(MouseEvent e) {
365     prevx = e.getX();
366     prevy = e.getY();
367     e.consume();
368   }
369   public void mouseReleased(MouseEvent e) {
370   }
371   public void mouseEntered(MouseEvent e) {
372   }
373   public void mouseExited(MouseEvent e) {
374   }
375   public void mouseDragged(MouseEvent e) {
376     int x = e.getX();
377     int y = e.getY();
378     tmat.unit();
379     float xtheta = (prevy - y) * (360.0f / getSize().width);
380     float ytheta = (x - prevx) * (360.0f / getSize().height);
381     tmat.xrot(xtheta);
382     tmat.yrot(ytheta);
383     amat.mult(tmat);
384     if (painted) {
385       painted = false;
386       repaint();
387     }
388     prevx = x;
389     prevy = y;
390     e.consume();
391   }
392   public void mouseMoved(MouseEvent e) {
393   }
394
395     public void update(Graphics JavaDoc g) {
396     if (backBuffer == null)
397         g.clearRect(0, 0, getSize().width, getSize().height);
398     paint(g);
399     }
400
401     public void paint(Graphics JavaDoc g) {
402     if (md != null) {
403         md.mat.unit();
404         md.mat.translate(-(md.xmin + md.xmax) / 2,
405                  -(md.ymin + md.ymax) / 2,
406                  -(md.zmin + md.zmax) / 2);
407         md.mat.mult(amat);
408         // md.mat.scale(xfac, -xfac, 8 * xfac / getSize().width);
409
md.mat.scale(xfac, -xfac, 16 * xfac / getSize().width);
410         md.mat.translate(getSize().width / 2, getSize().height / 2, 8);
411         md.transformed = false;
412         if (backBuffer != null) {
413         if (!backSize.equals(getSize()))
414             newBackBuffer();
415         backGC.setColor(getBackground());
416         backGC.fillRect(0,0,getSize().width,getSize().height);
417         md.paint(backGC);
418         g.drawImage(backBuffer, 0, 0, this);
419         }
420         else
421         md.paint(g);
422         setPainted();
423     } else if (message != null) {
424         g.drawString("Error in model:", 3, 20);
425         g.drawString(message, 10, 40);
426     }
427     }
428     private synchronized void setPainted() {
429     painted = true;
430     notifyAll();
431     }
432
433     private synchronized void waitPainted()
434     {
435        while (!painted)
436        {
437           try
438           {
439              wait();
440           }
441           catch (InterruptedException JavaDoc e) {}
442        }
443        painted = false;
444     }
445
446   public String JavaDoc getAppletInfo() {
447     return "Title: XYZApp \nAuthor: James Gosling \nAn applet to put a Chemical model into a page.";
448   }
449
450   public String JavaDoc[][] getParameterInfo() {
451     String JavaDoc[][] info = {
452       {"model", "path string", "The path to the model to be displayed in .xyz format (see http://chem.leeds.ac.uk/Project/MIME.html). Default is model.obj."},
453       {"scale", "float", "Scale factor. Default is 1 (i.e. no scale)."}
454     };
455     return info;
456   }
457 } // end class XYZApp
458

459 class Atom {
460     private static Applet JavaDoc applet;
461     private static byte[] data;
462     private final static int R = 40;
463     private final static int hx = 15;
464     private final static int hy = 15;
465     private final static int bgGrey = 192;
466     private final static int nBalls = 16;
467     private static int maxr;
468
469     private int Rl;
470     private int Gl;
471     private int Bl;
472     private Image JavaDoc balls[];
473
474     static {
475     data = new byte[R * 2 * R * 2];
476     int mr = 0;
477     for (int Y = 2 * R; --Y >= 0;) {
478         int x0 = (int) (Math.sqrt(R * R - (Y - R) * (Y - R)) + 0.5);
479         int p = Y * (R * 2) + R - x0;
480         for (int X = -x0; X < x0; X++) {
481         int x = X + hx;
482         int y = Y - R + hy;
483         int r = (int) (Math.sqrt(x * x + y * y) + 0.5);
484         if (r > mr)
485             mr = r;
486         data[p++] = r <= 0 ? 1 : (byte) r;
487         }
488     }
489     maxr = mr;
490     }
491     static void setApplet(Applet JavaDoc app) {
492     applet = app;
493     }
494     Atom(int Rl, int Gl, int Bl) {
495     this.Rl = Rl;
496     this.Gl = Gl;
497     this.Bl = Bl;
498     }
499     private final int blend(int fg, int bg, float fgfactor) {
500     return (int) (bg + (fg - bg) * fgfactor);
501     }
502     private void Setup() {
503     balls = new Image JavaDoc[nBalls];
504     byte red[] = new byte[256];
505     red[0] = (byte) bgGrey;
506     byte green[] = new byte[256];
507     green[0] = (byte) bgGrey;
508     byte blue[] = new byte[256];
509     blue[0] = (byte) bgGrey;
510     for (int r = 0; r < nBalls; r++) {
511         float b = (float) (r+1) / nBalls;
512         for (int i = maxr; i >= 1; --i) {
513         float d = (float) i / maxr;
514         red[i] = (byte) blend(blend(Rl, 255, d), bgGrey, b);
515         green[i] = (byte) blend(blend(Gl, 255, d), bgGrey, b);
516         blue[i] = (byte) blend(blend(Bl, 255, d), bgGrey, b);
517         }
518         IndexColorModel JavaDoc model = new IndexColorModel JavaDoc(8, maxr + 1,
519                             red, green, blue, 0);
520         balls[r] = applet.createImage(
521         new MemoryImageSource JavaDoc(R*2, R*2, model, data, 0, R*2));
522     }
523     }
524     void paint(Graphics JavaDoc gc, int x, int y, int r) {
525     Image JavaDoc ba[] = balls;
526     if (ba == null) {
527         Setup();
528         ba = balls;
529     }
530     Image JavaDoc i = ba[r];
531     int size = 10 + r;
532     gc.drawImage(i, x - (size >> 1), y - (size >> 1), size, size, applet);
533     }
534 }
535
Popular Tags