import java.awt.*; import java.applet.*; import java.io.*; import java.awt.event.*; interface DataListener { public void dataChanged(boolean satisfied); } public class Applet1 extends Applet { StrutGraph strutgraph = null; StrutViewer strutviewer = null; // entry point for frame version public static void main(String args[]) { Applet ap = new Applet1(); ap.init(); ap.start(); } // entry point for applet version public void init() { strutgraph = new StrutGraph(StephenNodeDat, StephenStrutDat, null); //strutgraph = new StrutGraph("blob.txt", null); strutviewer = new StrutViewer(strutgraph); strutgraph.setWatcher(strutviewer); // For Frame version, (search for "FRAMEVER" for places to change) // 1) make class DoubleBufferedFrame below // extend the Frame class instead of Panel, // 2) comment out these lines: // FRAMEVER setLayout(new BorderLayout()); strutviewer.setLayout(new BorderLayout()); add("Center", strutviewer); // FRAMEVER And 3) uncomment this one: //strutviewer.show(); strutgraph.start(); } public void start() { //strutviewer.pack(); //strutviewer.show(); //strutgraph.start(); } public void stop() { strutgraph.stop(); } public void destroy() { strutgraph.stop(); strutgraph.setWatcher(null); strutgraph = null; //strutviewer.dispose(); strutviewer = null; } /** * Some hardcoded data for use in applet */ static final double StephenNodeDat[][] = { {-8.5, 0, 0}, // 0 {8.5, 0, 0}, // 1 {0, -0.66612949304613, 8.4443040860981}, // 2 {0, -8.4443040860981, 0.66612949304613}, // 3 {-4.7963116268700, -9.2766868401806, -0.47515650470272}, // 4 { 4.7963116268700, 0.47515650470272, 9.2766868401806}, // 5 { 0.83494337199663, -0.71106403461286, 3.5147148078182}, // 6 {-0.83494337199663, -3.5147148078182, 0.71106403461286}, // 7 {0, -10.460722695081, 10.46072269508}, // 8 }; static final int StephenStrutDat[][] = { {0, 1, 17}, {0, 2, 12}, {1, 2, 12}, {0, 3, 12}, {1, 3, 12}, {0, 4, 10}, {1, 5, 10}, {0, 6, 10}, {1, 7, 10}, {2, 5, 5}, {5, 2, 5}, {3, 4, 5}, {4, 3, 5}, {2, 6, 5}, {6, 2, 5}, {3, 7, 5}, {7, 3, 5}, {4, 6, 11}, {6, 4, 11}, {5, 7, 11}, {7, 5, 11}, {2, 8, 10}, {8, 2, 10}, {3, 8, 10}, {8, 3, 10}, {4, 8, 12}, {8, 4, 12}, {5, 8, 12}, {8, 5, 12}, {6, 8, 12}, {8, 6, 12}, {7, 8, 12}, {8, 7, 12}, }; } class Node { public double pos[] = new double[3]; public double newpos[] = new double[3]; /* temporary for relax() */ public double scspos[] = new double[3]; /* temporary for graphics */ public Strut struts_ending_here; public Node(double dat[]) { Vec.SET3(pos, dat); } } class Strut { public double desiredlength; public Node from, to; /* force acts on "to" only */ public Strut rest; /* rest of struts beginning at from */ public Strut(double deslen, Node start, Node end) { desiredlength = deslen; from = start; to = end; rest = to.struts_ending_here; } public boolean isSatisfied() { double length = Math.sqrt(Vec.DISTSQRD3(from.pos, to.pos)); double diff = Math.abs(length - desiredlength); return diff < Vec.EPS; } } class StrutGraph extends Thread { public int nstruts = 0; public Strut[] struts = null; public Node[] nodes = null; private static double desired_position[] = new double[3]; DataListener watcher = null; public void setWatcher(DataListener dl) { watcher = dl; } public void run() { // so that graphics can have priority over computation: Thread.currentThread().setPriority(Thread.currentThread().getPriority() - 2); // main computational loop while(true) { relax(); boolean satisfied = isSatisfied(); if(watcher != null) watcher.dataChanged(satisfied); if(satisfied) try { sleep(250); } catch (java.lang.InterruptedException e) {} //System.out.println("relaxed"); } } public StrutGraph(double nodedat[][], int strutdat[][], DataListener dl) { for(int i=0; i= maxstruts) { System.out.println("too many struts"); return; } struts[nstruts] = new Strut(doublebuf, nodes[from], nodes[to]); nodes[to].struts_ending_here = struts[nstruts]; nstruts++; } } private boolean nextNumber(StreamTokenizer st) { try { if(StreamTokenizer.TT_NUMBER != st.nextToken()) return false; } catch(IOException ioe) { return false; } return true; } public void relax() { int i; for(i=0; i mMaxDir) mMaxDir = Math.abs(mNodes[i].pos[j]); } public void dataChanged(boolean satisfied) { if(mChanged) return; // already been notified, so don't stack up repaint requests mSatisfied = satisfied; mChanged = true; repaint(); } public void paint(Graphics gr) { mChanged = false; mScale = mOffscreenSize.width / mMaxDir * 0.4; Graphics g = startPaint(gr); g.setColor(Color.white); g.fillRect(0, 0, mOffscreenSize.width, mOffscreenSize.height); g.setColor(Color.black); double cx = mOffscreenSize.width / 2.0; double cy = mOffscreenSize.height / 2.0; for(int i=0; i .0001) { // do nothing if ended where we started Vec.VXS2(mAxis, mAxis, 1.0/len); mAxis[2] = 0; double rads = len / 200.0; Vec.MatFromQuat(mDeltaMat, mAxis, -rads); Vec.MXM3(mTmpMat, mDeltaMat, mMat); Vec.SETMAT3(mMat, mTmpMat); } mLastPoint[0] = mEnd[0]; mLastPoint[1] = mEnd[1]; mInverseDirty = true; } }