FileDocCategorySizeDatePackage
XYZChemModel.javaAPI DocExample5216Sat Apr 23 22:35:42 BST 2005magicbeans.sunw.demo.molecule

XYZChemModel.java

/*
 * A set of classes to parse, represent and display Chemical compounds in
 * .xyz format (see http://chem.leeds.ac.uk/Project/MIME.html)
 */
 // Made atomTable generic Map 12/2004 - Pat Niemeyer

package magicbeans.sunw.demo.molecule;

import java.io.*;
import java.util.*;


/** The representation of a Chemical .xyz model */
class XYZChemModel {
    float vert[];
    Atom atoms[];
    int tvert[];
    int ZsortMap[];
    int nvert, maxvert;

    static Map<String,Atom> atomTable = new HashMap<String,Atom>();
    static Atom defaultAtom;
    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;


    XYZChemModel () {
	mat = new Matrix3D();
	mat.xrot(20);
	mat.yrot(30);
    }


    /** Create a Chemical model by parsing an input stream */
    XYZChemModel (InputStream is) {
	this();
        try {
	    StreamTokenizer st = new StreamTokenizer(
			new BufferedReader(new InputStreamReader(is)));
	    st.eolIsSignificant(true);
	    st.commentChar('#');
	    int slot = 0;
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();
	        }
	    }
	    is.close();
	    if (st.ttype != StreamTokenizer.TT_EOF)
	        throw new Error(st.toString());
        } catch (Exception ex) {
    	    throw new Error("Input error: " + ex);
	}
    }

    /** Add a vertex to this model */
    int addVert(String name, float x, float y, float z) {
	int i = nvert;
	if (i >= maxvert)
	    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;
	    }
	Atom a = (Atom) atomTable.get(name.toLowerCase());
	if (a == null) a = defaultAtom;
	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() {
	if (transformed || nvert <= 0)
	    return;
	if (tvert == null || tvert.length < nvert * 3)
	    tvert = new int[nvert * 3];
	mat.transform(vert, tvert, nvert);
	transformed = true;
    }


    /**
     * Paint this model to a graphics context.  It uses the matrix associated
     * 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 
     */
    synchronized void paint(java.awt.Graphics g) {
	if (vert == null || nvert <= 0)
	    return;
	transform();
	int v[] = tvert;
	int zs[] = ZsortMap;
	if (zs == null) {
	    ZsortMap = zs = new int[nvert];
	    for (int i = nvert; --i >= 0;)
		zs[i] = i * 3;
	}

	/*
	 * 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;
		}
	    }
	    if (!flipped)
		break;
	}

	int lg = 0;
	int lim = nvert;
	Atom ls[] = atoms;
	if (lim <= 0 || nvert <= 0) {
	    return;
	}
	for (int i = 0; i < lim; i++) {
	    int j = zs[i];
	    int radius = v[j + 2];
	    if (radius < 0) {
		radius = 0;
	    } else if (radius > 15) {
		radius = 15;
	    }
	    atoms[j/3].paint(g, v[j], v[j + 1], radius);
	}
    }

    /** Find the bounding box of this model */
    void findBB() {
	if (nvert <= 0)
	    return;
	float v[] = vert;
	float xmin = v[0], xmax = xmin;
	float ymin = v[1], ymax = ymin;
	float zmin = v[2], zmax = zmin;
	for (int i = nvert * 3; (i -= 3) > 0;) {
	    float x = v[i];
	    if (x < xmin)
		xmin = x;
	    if (x > xmax)
		xmax = x;
	    float y = v[i + 1];
	    if (y < ymin)
		ymin = y;
	    if (y > ymax)
		ymax = y;
	    float z = v[i + 2];
	    if (z < zmin)
		zmin = z;
	    if (z > zmax)
		zmax = z;
	}
	this.xmax = xmax;
	this.xmin = xmin;
	this.ymax = ymax;
	this.ymin = ymin;
	this.zmax = zmax;
	this.zmin = zmin;
    }
}