XYZApp.java 17.0 KB
Newer Older
D
duke 已提交
1
/*
2
 * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
D
duke 已提交
3 4 5 6 7 8 9 10 11 12 13 14
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
15
 *   - Neither the name of Oracle nor the names of its
D
duke 已提交
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


import java.applet.Applet;
import java.awt.Image;
import java.awt.Graphics;
import java.awt.Dimension;
37 38 39
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
D
duke 已提交
40 41 42
import java.net.URL;
import java.awt.image.IndexColorModel;
import java.awt.image.MemoryImageSource;
43 44 45 46 47 48 49 50 51 52
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

D
duke 已提交
53

54 55 56 57
/*
 * A set of classes to parse, represent and display Chemical compounds in
 * .xyz format (see http://chem.leeds.ac.uk/Project/MIME.html)
 */
D
duke 已提交
58
/** The representation of a Chemical .xyz model */
59 60
final class XYZChemModel {

D
duke 已提交
61 62 63 64 65
    float vert[];
    Atom atoms[];
    int tvert[];
    int ZsortMap[];
    int nvert, maxvert;
66
    static final Map<String, Atom> atomTable = new HashMap<String, Atom>();
D
duke 已提交
67
    static Atom defaultAtom;
68

D
duke 已提交
69 70 71 72 73 74 75 76 77 78 79 80 81 82
    static {
        atomTable.put("c", new Atom(0, 0, 0));
        atomTable.put("h", new Atom(210, 210, 210));
        atomTable.put("n", new Atom(0, 0, 255));
        atomTable.put("o", new Atom(255, 0, 0));
        atomTable.put("p", new Atom(255, 0, 255));
        atomTable.put("s", new Atom(255, 255, 0));
        atomTable.put("hn", new Atom(150, 255, 150)); /* !!*/
        defaultAtom = new Atom(255, 100, 200);
    }
    boolean transformed;
    Matrix3D mat;
    float xmin, xmax, ymin, ymax, zmin, zmax;

83
    XYZChemModel() {
D
duke 已提交
84 85 86 87 88
        mat = new Matrix3D();
        mat.xrot(20);
        mat.yrot(30);
    }

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
    /** Create a Chemical model by parsing an input stream */
    XYZChemModel(InputStream is) throws Exception {
        this();
        StreamTokenizer st = new StreamTokenizer(
                new BufferedReader(new InputStreamReader(is, "UTF-8")));
        st.eolIsSignificant(true);
        st.commentChar('#');

        try {
            scan:
            while (true) {
                switch (st.nextToken()) {
                    case StreamTokenizer.TT_EOF:
                        break scan;
                    default:
                        break;
                    case StreamTokenizer.TT_WORD:
                        String name = st.sval;
                        double x = 0,
                         y = 0,
                         z = 0;
                        if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
                            x = st.nval;
                            if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
                                y = st.nval;
                                if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
                                    z = st.nval;
                                }
                            }
                        }
                        addVert(name, (float) x, (float) y, (float) z);
                        while (st.ttype != StreamTokenizer.TT_EOL
                                && st.ttype != StreamTokenizer.TT_EOF) {
                            st.nextToken();
                        }

                }   // end Switch

            }  // end while

            is.close();

        } // end Try
        catch (IOException e) {
        }
D
duke 已提交
134

135 136 137
        if (st.ttype != StreamTokenizer.TT_EOF) {
            throw new Exception(st.toString());
        }
D
duke 已提交
138 139 140 141 142 143

    }  // end XYZChemModel()

    /** Add a vertex to this model */
    int addVert(String name, float x, float y, float z) {
        int i = nvert;
144
        if (i >= maxvert) {
D
duke 已提交
145 146 147 148 149 150 151 152 153 154 155 156 157
            if (vert == null) {
                maxvert = 100;
                vert = new float[maxvert * 3];
                atoms = new Atom[maxvert];
            } else {
                maxvert *= 2;
                float nv[] = new float[maxvert * 3];
                System.arraycopy(vert, 0, nv, 0, vert.length);
                vert = nv;
                Atom na[] = new Atom[maxvert];
                System.arraycopy(atoms, 0, na, 0, atoms.length);
                atoms = na;
            }
158 159 160 161 162
        }
        Atom a = atomTable.get(name.toLowerCase());
        if (a == null) {
            a = defaultAtom;
        }
D
duke 已提交
163 164 165 166 167 168 169 170 171 172
        atoms[i] = a;
        i *= 3;
        vert[i] = x;
        vert[i + 1] = y;
        vert[i + 2] = z;
        return nvert++;
    }

    /** Transform all the points in this model */
    void transform() {
173
        if (transformed || nvert <= 0) {
D
duke 已提交
174
            return;
175 176
        }
        if (tvert == null || tvert.length < nvert * 3) {
D
duke 已提交
177
            tvert = new int[nvert * 3];
178
        }
D
duke 已提交
179 180 181 182 183
        mat.transform(vert, tvert, nvert);
        transformed = true;
    }

    /** Paint this model to a graphics context.  It uses the matrix associated
184 185 186
    with this model to map from model space to screen space.
    The next version of the browser should have double buffering,
    which will make this *much* nicer */
D
duke 已提交
187
    void paint(Graphics g) {
188
        if (vert == null || nvert <= 0) {
D
duke 已提交
189
            return;
190
        }
D
duke 已提交
191 192 193 194 195
        transform();
        int v[] = tvert;
        int zs[] = ZsortMap;
        if (zs == null) {
            ZsortMap = zs = new int[nvert];
196
            for (int i = nvert; --i >= 0;) {
D
duke 已提交
197
                zs[i] = i * 3;
198
            }
D
duke 已提交
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
        }

        /*
         * I use a bubble sort since from one iteration to the next, the sort
         * order is pretty stable, so I just use what I had last time as a
         * "guess" of the sorted order.  With luck, this reduces O(N log N)
         * to O(N)
         */

        for (int i = nvert - 1; --i >= 0;) {
            boolean flipped = false;
            for (int j = 0; j <= i; j++) {
                int a = zs[j];
                int b = zs[j + 1];
                if (v[a + 2] > v[b + 2]) {
                    zs[j + 1] = a;
                    zs[j] = b;
                    flipped = true;
                }
            }
219
            if (!flipped) {
D
duke 已提交
220
                break;
221
            }
D
duke 已提交
222 223 224
        }

        int lim = nvert;
225
        if (lim <= 0 || nvert <= 0) {
D
duke 已提交
226
            return;
227
        }
D
duke 已提交
228 229 230
        for (int i = 0; i < lim; i++) {
            int j = zs[i];
            int grey = v[j + 2];
231
            if (grey < 0) {
D
duke 已提交
232
                grey = 0;
233 234
            }
            if (grey > 15) {
D
duke 已提交
235
                grey = 15;
236
            }
D
duke 已提交
237
            // g.drawString(names[i], v[j], v[j+1]);
238
            atoms[j / 3].paint(g, v[j], v[j + 1], grey);
D
duke 已提交
239 240 241 242 243 244 245
            // g.drawImage(iBall, v[j] - (iBall.width >> 1), v[j + 1] -
            // (iBall.height >> 1));
        }
    }

    /** Find the bounding box of this model */
    void findBB() {
246
        if (nvert <= 0) {
D
duke 已提交
247
            return;
248
        }
D
duke 已提交
249
        float v[] = vert;
250 251 252
        float _xmin = v[0], _xmax = _xmin;
        float _ymin = v[1], _ymax = _ymin;
        float _zmin = v[2], _zmax = _zmin;
D
duke 已提交
253 254
        for (int i = nvert * 3; (i -= 3) > 0;) {
            float x = v[i];
255 256 257 258 259 260
            if (x < _xmin) {
                _xmin = x;
            }
            if (x > _xmax) {
                _xmax = x;
            }
D
duke 已提交
261
            float y = v[i + 1];
262 263 264 265 266 267
            if (y < _ymin) {
                _ymin = y;
            }
            if (y > _ymax) {
                _ymax = y;
            }
D
duke 已提交
268
            float z = v[i + 2];
269 270 271 272 273 274
            if (z < _zmin) {
                _zmin = z;
            }
            if (z > _zmax) {
                _zmax = z;
            }
D
duke 已提交
275
        }
276 277 278 279 280 281
        this.xmax = _xmax;
        this.xmin = _xmin;
        this.ymax = _ymax;
        this.ymin = _ymin;
        this.zmax = _zmax;
        this.zmin = _zmin;
D
duke 已提交
282 283 284
    }
}

285

D
duke 已提交
286
/** An applet to put a Chemical model into a page */
287 288 289 290
@SuppressWarnings("serial")
public class XYZApp extends Applet implements Runnable, MouseListener,
        MouseMotionListener {

D
duke 已提交
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
    XYZChemModel md;
    boolean painted = true;
    float xfac;
    int prevx, prevy;
    float scalefudge = 1;
    Matrix3D amat = new Matrix3D(), tmat = new Matrix3D();
    String mdname = null;
    String message = null;
    Image backBuffer;
    Graphics backGC;
    Dimension backSize;

    private synchronized void newBackBuffer() {
        backBuffer = createImage(getSize().width, getSize().height);
        if (backGC != null) {
            backGC.dispose();
        }
        backGC = backBuffer.getGraphics();
        backSize = getSize();
    }

312
    @Override
D
duke 已提交
313 314 315 316
    public void init() {
        mdname = getParameter("model");
        try {
            scalefudge = Float.valueOf(getParameter("scale")).floatValue();
317 318
        } catch (Exception ignored) {
        }
D
duke 已提交
319 320
        amat.yrot(20);
        amat.xrot(20);
321
        if (mdname == null) {
D
duke 已提交
322
            mdname = "model.obj";
323
        }
D
duke 已提交
324
        resize(getSize().width <= 20 ? 400 : getSize().width,
325
                getSize().height <= 20 ? 400 : getSize().height);
D
duke 已提交
326 327 328 329 330
        newBackBuffer();
        addMouseListener(this);
        addMouseMotionListener(this);
    }

331
    @Override
D
duke 已提交
332 333 334 335 336
    public void destroy() {
        removeMouseListener(this);
        removeMouseMotionListener(this);
    }

337
    @Override
D
duke 已提交
338 339 340 341 342
    public void run() {
        InputStream is = null;
        try {
            Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
            is = new URL(getDocumentBase(), mdname).openStream();
343
            XYZChemModel m = new XYZChemModel(is);
D
duke 已提交
344 345 346 347 348 349
            Atom.setApplet(this);
            md = m;
            m.findBB();
            float xw = m.xmax - m.xmin;
            float yw = m.ymax - m.ymin;
            float zw = m.zmax - m.zmin;
350
            if (yw > xw) {
D
duke 已提交
351
                xw = yw;
352 353
            }
            if (zw > xw) {
D
duke 已提交
354
                xw = zw;
355
            }
D
duke 已提交
356 357 358
            float f1 = getSize().width / xw;
            float f2 = getSize().height / xw;
            xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge;
359 360
        } catch (Exception e) {
            Logger.getLogger(XYZApp.class.getName()).log(Level.SEVERE, null, e);
D
duke 已提交
361 362 363 364
            md = null;
            message = e.toString();
        }
        try {
365
            if (is != null) {
D
duke 已提交
366
                is.close();
367 368
            }
        } catch (Exception ignored) {
D
duke 已提交
369 370 371
        }
        repaint();
    }
372 373

    @Override
D
duke 已提交
374
    public void start() {
375
        if (md == null && message == null) {
D
duke 已提交
376
            new Thread(this).start();
377
        }
D
duke 已提交
378
    }
379 380

    @Override
D
duke 已提交
381 382
    public void stop() {
    }
383 384 385 386
    /* event handling */

    @Override
    public void mouseClicked(MouseEvent e) {
D
duke 已提交
387 388
    }

389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
    @Override
    public void mousePressed(MouseEvent e) {
        prevx = e.getX();
        prevy = e.getY();
        e.consume();
    }

    @Override
    public void mouseReleased(MouseEvent e) {
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        int x = e.getX();
        int y = e.getY();
        tmat.unit();
        float xtheta = (prevy - y) * (360.0f / getSize().width);
        float ytheta = (x - prevx) * (360.0f / getSize().height);
        tmat.xrot(xtheta);
        tmat.yrot(ytheta);
        amat.mult(tmat);
        if (painted) {
            painted = false;
            repaint();
        }
        prevx = x;
        prevy = y;
        e.consume();
    }

    @Override
    public void mouseMoved(MouseEvent e) {
    }

    @Override
D
duke 已提交
432
    public void update(Graphics g) {
433
        if (backBuffer == null) {
D
duke 已提交
434
            g.clearRect(0, 0, getSize().width, getSize().height);
435
        }
D
duke 已提交
436 437 438
        paint(g);
    }

439
    @Override
D
duke 已提交
440 441 442 443
    public void paint(Graphics g) {
        if (md != null) {
            md.mat.unit();
            md.mat.translate(-(md.xmin + md.xmax) / 2,
444 445
                    -(md.ymin + md.ymax) / 2,
                    -(md.zmin + md.zmax) / 2);
D
duke 已提交
446 447 448 449 450 451
            md.mat.mult(amat);
            // md.mat.scale(xfac, -xfac, 8 * xfac / getSize().width);
            md.mat.scale(xfac, -xfac, 16 * xfac / getSize().width);
            md.mat.translate(getSize().width / 2, getSize().height / 2, 8);
            md.transformed = false;
            if (backBuffer != null) {
452
                if (!backSize.equals(getSize())) {
D
duke 已提交
453
                    newBackBuffer();
454
                }
D
duke 已提交
455
                backGC.setColor(getBackground());
456
                backGC.fillRect(0, 0, getSize().width, getSize().height);
D
duke 已提交
457 458
                md.paint(backGC);
                g.drawImage(backBuffer, 0, 0, this);
459
            } else {
D
duke 已提交
460
                md.paint(g);
461
            }
D
duke 已提交
462 463 464 465 466 467
            setPainted();
        } else if (message != null) {
            g.drawString("Error in model:", 3, 20);
            g.drawString(message, 10, 40);
        }
    }
468

D
duke 已提交
469 470 471 472 473
    private synchronized void setPainted() {
        painted = true;
        notifyAll();
    }

474 475 476 477
    @Override
    public String getAppletInfo() {
        return "Title: XYZApp \nAuthor: James Gosling \nAn applet to put"
                + " a Chemical model into a page.";
D
duke 已提交
478 479
    }

480 481 482 483 484 485 486 487 488 489 490
    @Override
    public String[][] getParameterInfo() {
        String[][] info = {
            { "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." },
            { "scale", "float", "Scale factor.  Default is 1 (i.e. no scale)." }
        };
        return info;
    }
D
duke 已提交
491 492
}   // end class XYZApp

493

D
duke 已提交
494
class Atom {
495

D
duke 已提交
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
    private static Applet applet;
    private static byte[] data;
    private final static int R = 40;
    private final static int hx = 15;
    private final static int hy = 15;
    private final static int bgGrey = 192;
    private final static int nBalls = 16;
    private static int maxr;
    private int Rl;
    private int Gl;
    private int Bl;
    private Image balls[];

    static {
        data = new byte[R * 2 * R * 2];
        int mr = 0;
        for (int Y = 2 * R; --Y >= 0;) {
            int x0 = (int) (Math.sqrt(R * R - (Y - R) * (Y - R)) + 0.5);
            int p = Y * (R * 2) + R - x0;
            for (int X = -x0; X < x0; X++) {
                int x = X + hx;
                int y = Y - R + hy;
                int r = (int) (Math.sqrt(x * x + y * y) + 0.5);
519
                if (r > mr) {
D
duke 已提交
520
                    mr = r;
521
                }
D
duke 已提交
522 523 524 525 526
                data[p++] = r <= 0 ? 1 : (byte) r;
            }
        }
        maxr = mr;
    }
527

D
duke 已提交
528 529 530
    static void setApplet(Applet app) {
        applet = app;
    }
531

D
duke 已提交
532 533 534 535 536
    Atom(int Rl, int Gl, int Bl) {
        this.Rl = Rl;
        this.Gl = Gl;
        this.Bl = Bl;
    }
537 538

    private int blend(int fg, int bg, float fgfactor) {
D
duke 已提交
539 540
        return (int) (bg + (fg - bg) * fgfactor);
    }
541

D
duke 已提交
542 543 544 545 546 547 548 549 550
    private void Setup() {
        balls = new Image[nBalls];
        byte red[] = new byte[256];
        red[0] = (byte) bgGrey;
        byte green[] = new byte[256];
        green[0] = (byte) bgGrey;
        byte blue[] = new byte[256];
        blue[0] = (byte) bgGrey;
        for (int r = 0; r < nBalls; r++) {
551
            float b = (float) (r + 1) / nBalls;
D
duke 已提交
552 553 554 555 556 557 558
            for (int i = maxr; i >= 1; --i) {
                float d = (float) i / maxr;
                red[i] = (byte) blend(blend(Rl, 255, d), bgGrey, b);
                green[i] = (byte) blend(blend(Gl, 255, d), bgGrey, b);
                blue[i] = (byte) blend(blend(Bl, 255, d), bgGrey, b);
            }
            IndexColorModel model = new IndexColorModel(8, maxr + 1,
559
                    red, green, blue, 0);
D
duke 已提交
560
            balls[r] = applet.createImage(
561
                    new MemoryImageSource(R * 2, R * 2, model, data, 0, R * 2));
D
duke 已提交
562 563
        }
    }
564

D
duke 已提交
565 566 567 568 569 570 571 572 573 574 575
    void paint(Graphics gc, int x, int y, int r) {
        Image ba[] = balls;
        if (ba == null) {
            Setup();
            ba = balls;
        }
        Image i = ba[r];
        int size = 10 + r;
        gc.drawImage(i, x - (size >> 1), y - (size >> 1), size, size, applet);
    }
}