Crossfire JXClient, Trunk
XYZApp.java
Go to the documentation of this file.
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  */
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 
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 
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 
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 
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 
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 
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 final static int R = 40;
508  private final static int hx = 15;
509  private final static int hy = 15;
510  private final static int bgGrey = 192;
511  private final static 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 }
XYZApp.newBackBuffer
synchronized void newBackBuffer()
Definition: XYZApp.java:312
XYZApp.mousePressed
void mousePressed(MouseEvent e)
Definition: XYZApp.java:399
XYZApp.getAppletInfo
String getAppletInfo()
Definition: XYZApp.java:484
XYZApp.mouseMoved
void mouseMoved(MouseEvent e)
Definition: XYZApp.java:437
XYZApp.run
void run()
Definition: XYZApp.java:347
XYZApp.mouseExited
void mouseExited(MouseEvent e)
Definition: XYZApp.java:414
XYZApp.mouseReleased
void mouseReleased(MouseEvent e)
Definition: XYZApp.java:406
XYZApp.destroy
void destroy()
Definition: XYZApp.java:341
XYZApp.mouseClicked
void mouseClicked(MouseEvent e)
Definition: XYZApp.java:395
XYZApp.mouseDragged
void mouseDragged(MouseEvent e)
Definition: XYZApp.java:418
XYZApp.stop
void stop()
Definition: XYZApp.java:390
XYZApp.setPainted
synchronized void setPainted()
Definition: XYZApp.java:478
XYZApp
Definition: XYZApp.java:297
XYZApp.start
void start()
Definition: XYZApp.java:383
XYZApp.init
void init()
Definition: XYZApp.java:322
XYZApp.getParameterInfo
String[][] getParameterInfo()
Definition: XYZApp.java:490
XYZApp.update
void update(Graphics g)
Definition: XYZApp.java:441
XYZApp.mouseEntered
void mouseEntered(MouseEvent e)
Definition: XYZApp.java:410
XYZApp.paint
void paint(Graphics g)
Definition: XYZApp.java:449