import java.awt.*; import java.applet.Applet; import java.util.Vector; import java.util.Enumeration; /* Spider.java ( 1.02 ) * * All the usual health warnings. * (c) Chris Davis 1998 */ public class IdleSpider extends Applet implements Runnable { Runtime runtime; long freeMem; int frameNumber = -1; int delay; Thread animatorThread; boolean frozen = true; Dimension offDimension; Image offImage, fieldImage; public Graphics offGraphics, fieldGraphics; public int dr = 1; Field field; WebCanvas canvas1; GraphCanvas canvas2; Button b1; Label counter; Choice c1; int currentChoice = 0; // selected Choice index no. boolean actionChoice = false; // true to do something about it public int p_type[] = new int[10]; public int p_reduceflysize, p_flysize, p_scale; public String getAppletInfo() { return "IdleSpider Evolution Simulation V.1.0\r\n" + "Created using JDK 1.0.2 by Chris Davis, 30 dec 1998\r\n"; } // initialization reads parameters, sets up screen layouts. public void init() { String str; int gridsize; Dimension d = size(); gridsize = d.width / 20; // spider and web field initialization field = new Field( this ); // set up the GUI GridBagLayout gridBag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); setLayout(gridBag); b1 = new Button(" Start "); c.gridwidth = GridBagConstraints.EAST; c.gridx = 0; c.gridy = 0; c.gridwidth = 1; c.gridheight= 1; c.weightx = 1.0; c.weighty = 0.0; gridBag.setConstraints(b1, c); add(b1); c1 = new Choice(); c1.addItem("Increase fly size"); c1.addItem("Decrease fly size"); c1.addItem("Increase yarn strength"); c1.addItem("Decrease yarn strength"); c1.addItem("Increase parameter 1"); c1.addItem("Decrease parameter 1"); c1.addItem("Increase parameter 2"); c1.addItem("Decrease parameter 2"); c1.addItem("Toggle 1 or 9 webs"); c.fill = GridBagConstraints.BOTH; c.gridx = 1; c.gridy = 0; c.gridwidth = 2; c.gridheight= 1; c.weightx = 1.0; c.weighty = 1.0; gridBag.setConstraints(c1, c); add(c1); canvas1 = new WebCanvas(field); canvas1.resize( d.width, d.width ); c.fill = GridBagConstraints.BOTH; c.gridx = 0; c.gridy = 1; c.gridwidth = 5; c.gridheight= 1; c.weightx = 1.0; c.weighty = 1.0; gridBag.setConstraints(canvas1, c); add(canvas1); canvas2 = new GraphCanvas(field); canvas2.resize( d.width, 100 ); c.fill = GridBagConstraints.BOTH; c.gridx = 0; c.gridy = 2; c.gridwidth = 5; c.gridheight= 1; c.weightx = 1.0; c.weighty = 1.0; gridBag.setConstraints(canvas2, c); add(canvas2); validate(); // get spider types for ( int pn = 1; pn < 10; pn++ ) { try { p_type[pn] = Integer.parseInt( getParameter("TYPE" + Integer.toString(pn) ) ); } catch( Exception e ) { p_type[pn] = 1; // perimeter spider default } } // get reduceflysize try { p_reduceflysize = Integer.parseInt( getParameter("REDUCE") ); } catch( Exception e ) { p_reduceflysize = 0; } // get flysize try { p_flysize = Integer.parseInt( getParameter("FLYSIZE") ); } catch( Exception e ) { p_flysize = 120; } // get scale factor for perimeter walk try { p_scale = Integer.parseInt( getParameter("SCALE") ); } catch( Exception e ) { p_scale = 20; } field.init(); } void showFreeMem() { runtime = Runtime.getRuntime(); freeMem = runtime.freeMemory() / 1024; // System.out.println(" Free mem: " + freeMem + "K" ); System.gc(); } public void start() { if (animatorThread == null) { animatorThread = new Thread(this); animatorThread.start(); } } public void stop() { if ( animatorThread != null ) { animatorThread.stop(); animatorThread = null; } } public void destroy() { } public boolean mouseDown(Event e, int x, int y) { return true; } public boolean action(Event e, Object arg) { // start/stop button if ( e.target == b1 ) { frozen = !frozen; if ( frozen ) { b1.setLabel("Start"); } else { b1.setLabel("Stop"); } } // choice list if ( e.target == c1 ) { System.out.println( (String)e.arg ); currentChoice = c1.getSelectedIndex(); actionChoice = true; // if frozen ( perhaps only just init'd ) perform choice action // immediately, else do in main loop engine. if ( frozen == true ) { actionChoice = field.doChoiceAction( currentChoice ); } } return true; } public void run() { Thread.currentThread().setPriority(Thread.MIN_PRIORITY); while (Thread.currentThread() == animatorThread) { try { if ( !frozen ) { //Advance the animation frame. frameNumber++; repaint(); // Grow the field field.engine( offGraphics ); // Display field. canvas1.repaint(); // Display graphs canvas2.repaint(); animatorThread.sleep(100); } else { animatorThread.sleep(1000); } } catch ( InterruptedException e ) { stop(); } } } } class Silk { public double x1; // one end of silk yarn public double y1; public double x2; // other end of silk yarn public double y2; public double l; // silk yarn length public double age; // yarn age public double maxage; // yarn maximum age /* silk thread constructor */ public Silk( double x1, double y1, double x2, double y2 , double maxage ) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.l = Math.sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) ); this.age = 0; this.maxage = maxage; } /* age silk yarn, returning true when over max age */ public boolean ageSilk() { boolean b = false; this.age++; if ( this.age > this.maxage ) b = true; return(b); } } class Spider { public int uniqueID; // unique spider identity public boolean alive; // spider live/dead status public boolean busy; // spider idle/busy public int age; // spider age public double x; // spider x location public double y; // spider y location public double webwidth; // spider web width public double webheight; // spider web height public double energystore; // spider energy store public double energystoreTotal; // running total energy store public int busytimeTotal; // running total busy time public double bmr; // spider basic metabolic rate public double e_in; // energy income over lifetime public double e_out; // energy outgo .. .. public double busy_time; // lifetime busy public double repstart; // energy level above which spider reproduces public double webstart; // .. .. below which spider builds web public double webstop; // .. .. below .. spider stops webbuild public double walk; // webwidth walk fraction public double yarncost; // yarn thickness (& durability) public int webtype; // type of web built public double perimeterMove[] = new double[4]; public double xfly; // fly location public double yfly; public double rfly; // fly radius (and hence body mass) public boolean caughtfly; public double rect[][] = new double[5][2]; public Vector web = new Vector(); // list of silk yarns in web /* default spider constructor*/ public Spider() { } /* Spider constructor */ public Spider( int id, int wtype, int ytype, double walk ) { this.uniqueID = id; this.alive = true; this.age = 0; this.x = 0; this.y = 0; this.bmr = 5.0; this.webwidth = 100.0; this.webheight = 100.0; this.yarncost = (double)ytype / 100.0; this.webstart = 10000.0 * this.yarncost; // start earlier with heavy yarn this.energystore = this.webstart; // energy level below which to build web this.energystoreTotal = 0.0; this.busytimeTotal = 0; this.webstop = 0.0; this.webtype = wtype; this.walk = walk; this.perimeterMove[0] = walk * this.webwidth; // start web move if ( this.webtype == 2 ) this.perimeterMove[0] = 1.05 * this.webwidth; this.perimeterMove[1] = 1.0; // sense (1.0=clockwise) this.perimeterMove[2] = 0.00 * this.webwidth; // ladder move A this.perimeterMove[3] = walk * 5.0; // ladder move B this.e_in = 0; this.e_out = 0; this.busy_time = 0; // define web limits rect[0][0] = 0; rect[0][1] = 0; rect[1][0] = webwidth-1; rect[1][1] = 0; rect[2][0] = webwidth-1; rect[2][1] = webheight-1; rect[3][0] = 0; rect[3][1] = webwidth-1; rect[4][0] = 0; rect[4][1] = 0; } /* burn up bmr energy, and return spider live/dead status */ public boolean stayAlive() { this.age++; this.energystore -= this.bmr; if ( this.energystore <= 0 ) this.alive = false; return( this.alive ); } /* build web of some sort */ public boolean buildWeb() { boolean built = false; if ( this.webtype == 0 ) built = buildRandomWeb(); if ( this.webtype == 1 ) built = buildPerimeterWeb(); if ( this.webtype == 2 ) built = buildLastStrandWeb(); return( built ); } /* build random web by walking random distance round perimeter */ public boolean buildRandomWeb() { Silk s; double d, x, y, xstart, ystart; boolean yarnspun = false; xstart = this.x; ystart = this.y; this.movePerimeterSpider( this.perimeterMove[1] * this.perimeterMove[0] * Math.random() ); s = new Silk( xstart, ystart, this.x, this.y, yarncost*400.0 ); this.web.addElement(s); yarnspun = true; if ( yarnspun) { d = Math.sqrt( (this.x-xstart)*(this.x-xstart) + (this.y-ystart)*(this.y-ystart) ); } else d = 0; this.energystore -= d * yarncost; // energy cost of building web this.e_out += d * yarncost; // add to total energy output return( true ); } /* build a web by walking some fixed distance round perimeter for each strand */ public boolean buildPerimeterWeb() { Silk s; double d, x, y, xstart, ystart; boolean yarnspun = false; xstart = this.x; ystart = this.y; this.movePerimeterSpider( this.perimeterMove[1] * this.perimeterMove[0] ); s = new Silk( xstart, ystart, this.x, this.y, yarncost*400.0 ); this.web.addElement(s); yarnspun = true; if ( yarnspun) { d = Math.sqrt( (this.x-xstart)*(this.x-xstart) + (this.y-ystart)*(this.y-ystart) ); } else d = 0; this.energystore -= d * yarncost; // energy cost of building web this.e_out += d * yarncost; // add to total energy output return( true ); } /* build a web by using the last strand made to cross the gap */ public boolean buildLastStrandWeb() { Silk s; double d, x, y, xstart, ystart; boolean yarnspun = false; if ( this.web.size() == 0 ) { this.x = 0; this.y = 0; this.perimeterMove[1] = 1.0; xstart = this.x; ystart = this.y; this.movePerimeterSpider( this.perimeterMove[0] ); s = new Silk( xstart, ystart, this.x, this.y, yarncost*400.0 ); this.web.addElement(s); yarnspun = true; } else { Silk yarn = (Silk)web.elementAt(this.web.size()-1); this.x = yarn.x2; this.y = yarn.y2; this.movePerimeterSpider( this.perimeterMove[1] * this.perimeterMove[2] ); xstart = this.x; ystart = this.y; this.x = yarn.x1; this.y = yarn.y1; this.movePerimeterSpider( this.perimeterMove[1] * this.perimeterMove[3] ); if ( (xstart!=this.x) && (ystart != this.y) ) { // this.movePerimeterSpider( this.perimeterMove[1] * this.perimeterMove[3] ); s = new Silk( xstart, ystart, this.x, this.y, yarncost*400.0 ); this.web.addElement(s); yarnspun = true; } } this.perimeterMove[1] = -this.perimeterMove[1]; if ( yarnspun) { d = Math.sqrt( (this.x-xstart)*(this.x-xstart) + (this.y-ystart)*(this.y-ystart) ); } else d = 0; this.energystore -= d * yarncost; // energy cost of building web this.e_out += d * yarncost; return( true ); } /* move spider from point P some +-distance around perimeter of rectangle */ public void movePerimeterSpider( double distance ) { int n, p, p1; double xa, ya, yi, xi, l, sy, sx, dist; double x = this.x; double y = this.y; double d = Math.abs(distance); int sense = (int)(distance / Math.abs(distance)); if ( sense == 1 ) p1 = 0; else p1 = 4; while ( d > 0 ) { xa = x; ya = y; boolean found = false; for ( n = 0; n <=4; n++ ) { p = p1 + sense * n; xi = this.rect[p][0]; yi = this.rect[p][1]; /* check if between two successive corners */ if ( ((x==xi) && (y!=yi)) || ((x!=xi) && (y==yi)) ) { xa = this.rect[p][0]; ya = this.rect[p][1]; if ( found ) break; found = true; } else { found = false; /* check if at corner */ if ( (x==xi) && (y==yi) ) { xa = this.rect[p1+sense*(n+1)][0]; ya = this.rect[p1+sense*(n+1)][1]; break; } } } l = Math.sqrt( (x-xa)*(x-xa) + (y-ya)*(y-ya) ); sx = xa - x; if (sx!=0) sx = sx / Math.abs(sx); sy = ya - y; if (sy!=0) sy = sy / Math.abs(sy); if ( l > d ) dist = d; else dist = l; x = x + sx * dist; y = y + sy * dist; d = d - dist; } this.x = x; this.y = y; } /* find if fly of radius r at (x,y) hits any strand in web */ /* this code SHOULD check if past ends of strand!! */ public boolean catchFly( double x, double y, double r ) { Silk yarn; double xa, xb, ya, yb, a2, b2, c2, d2, f; double signxa, signxb, signya, signyb; boolean hit = false; this.xfly = x; this.yfly = y; this.rfly = r; this.caughtfly = false; for ( int t = 0; t < web.size(); t++ ) { yarn = (Silk)web.elementAt(t); xa = x - yarn.x1; signxa = xa/xa; xb = x - yarn.x2; signxb = xb/xb; ya = y - yarn.y1; signya = ya/ya; yb = y - yarn.y2; signyb = yb/yb; a2 = xa*xa + ya*ya; // dist A squared b2 = xb*xb + yb*yb; // dist B squared c2 = yarn.l * yarn.l; // yarn length squared f = (a2 - b2 + c2)/(2.0 * c2); // fraction of yarn length to nearpoint d2 = a2 - f*f*c2; // dist of fly from yarn squared if ( (r*r) > d2 ) { hit = true; this.caughtfly = true; break; } } if ( hit ) { this.energystore += r*r*r*100.0; // eat the fly this.e_in += r*r*r*100.0; } return( hit ); } /* paint the spider web and fly */ public void paintWeb( boolean select, Graphics offGraphics, double x0, double y0, double width, double height ) { Silk yarn; double xs, ys; xs = width/webwidth; ys = height/webheight; offGraphics.setPaintMode(); offGraphics.setColor(Color.darkGray); offGraphics.fillRect( (int)x0, (int)y0, (int)(width)+1, (int)(height)+1 ); if (select) offGraphics.setColor(Color.cyan); else offGraphics.setColor(Color.white); for ( int n = 0; n < web.size(); n++ ) { yarn = (Silk)web.elementAt(n); offGraphics.drawLine( (int)(x0+yarn.x1*xs), (int)(y0+yarn.y1*ys), (int)(x0+yarn.x2*xs), (int)(y0+yarn.y2*ys) ); } if ( caughtfly ) offGraphics.setColor(Color.red); else offGraphics.setColor(Color.green); offGraphics.fillOval( (int)(x0+(xfly-rfly)*xs), (int)(y0+(yfly-rfly)*ys), (int)(2*rfly*xs), (int)(2*rfly*ys) ); offGraphics.setColor(Color.red); offGraphics.drawString( Integer.toString(this.uniqueID), (int)x0+2, (int)y0+12 ); } /* Idle Theory calculated idleness = 1 - Wm / ( Wi - We ) */ public int idleness() { double i = 1.0 - ( this.bmr / ( (this.e_in/this.busy_time) - (this.e_out/this.busy_time) ) ); return( (int)(100.0 * i) ); } /* spider is observed busy if making web or eating fly */ public int observedIdleness() { double i = 1.0 - this.busy_time/(double)this.age; return( (int)(100.0 * i) ); } /* add to running total energystore */ public void addEnergystoreTotal() { this.energystoreTotal += this.energystore; } /* reset running total energystore */ public void resetEnergystoreTotal () { this.energystoreTotal = 0.0; } /* increment running total observed busy times */ public void incBusytime() { this.busy_time++; this.busytimeTotal++; } /* reset observed busytimeTotal */ public void resetBusytimeTotal() { this.busytimeTotal = 0; } } /******* Field class initializes field and runs main simulation engine ******/ class Field { public boolean inited = false; IdleSpider thisApplet; public Vector v = new Vector(); public int nspiders; public int uniqueID = 0; public double displayStream[] = new double[5]; public int selectedDisplayElement; public int selectedDisplayID = 9; public int numSpidersSeen = 9; public int time = 0; public int checkInterval; public boolean reduceFlySize = false; int webwidth = 100; int webheight = 100; double xfly, yfly, rfly, rflyMax; // fly location and radius String displayString[] = new String[10]; /* Constructor allows access to Applet */ public Field( IdleSpider a ) { super(); thisApplet = a; } /* Field initialization with spiders */ public void init() { Spider spider; /* initialize some spiders */ nspiders = 0; double scale = (double)thisApplet.p_scale / 10.0; for ( int n = 1; n <= 9; n++ ) { spider = new Spider( ++uniqueID, thisApplet.p_type[n] , 25, Math.random() * scale ); v.addElement(spider); nspiders++; } rflyMax = (double)thisApplet.p_flysize / 100.0; // fly radius rfly = rflyMax; if ( thisApplet.p_reduceflysize != 0 ) reduceFlySize = true; // this gradually reduces fly radius checkInterval = 500; inited=true; } /* the simulation engine room */ public void engine(Graphics offGraphics) { int n; Spider spider; Silk yarn; /* action any selected Choices */ if ( thisApplet.actionChoice ) thisApplet.actionChoice = doChoiceAction( thisApplet.currentChoice ); /* new fly of radius rfly buzzes thru web at location xfly,yfly */ xfly = Math.random() * (webwidth-1); yfly = Math.random() * (webheight-1); /* spider bmr and still-alive checks */ if ( v.size() > 0 ) { for ( n = 0; n < v.size(); n++ ) { spider = (Spider)v.elementAt(n); spider.busy = false; if ( !spider.stayAlive() ) { v.removeElementAt(n); int template = (int)(Math.random()*6.999); Spider templateSpider = (Spider)v.elementAt( template ); double change = 1.0 + (Math.random()*0.1 - 0.05); spider = new Spider( ++uniqueID, templateSpider.webtype, 25, templateSpider.walk * change ); v.addElement(spider); System.out.println( "New "+ uniqueID + " is " + change + " of ID " + templateSpider.uniqueID+": "+templateSpider.perimeterMove[0] ); } } } /* spider catches fly, builds web, or does nothing */ if ( v.size() > 0 ) { for ( n = 0; n < v.size(); n++ ) { spider = (Spider)v.elementAt(n); if ( !spider.catchFly( xfly, yfly, rfly) ) { if ( spider.energystore < spider.webstart ) { if ( spider.energystore > spider.webstop ) { spider.busy = spider.buildWeb(); } } } else spider.busy = true; if ( spider.busy ) spider.incBusytime(); /* remove aged silk from web */ for ( int t = 0; t < spider.web.size(); t++ ) { yarn = (Silk)spider.web.elementAt(t); if ( yarn.ageSilk() ) { spider.web.removeElementAt( t ); } } } } /* change fly radius depending on spider av. energy store over past 100 timeunits */ if ( v.size() > 0 ) { double efraction = 0.0; int numOldSpiders = 0; for ( n = 0; n < v.size(); n++ ) { spider = (Spider)v.elementAt(n); if ( (time % checkInterval) == 0 ) { /* Young spiders start with high energy stores, ignore them */ if ( spider.age >= (checkInterval-1) ) { efraction += spider.energystoreTotal / ( (double)checkInterval * spider.webstart ); numOldSpiders++; } spider.resetEnergystoreTotal(); spider.resetBusytimeTotal(); } spider.addEnergystoreTotal(); } if ( ((time % checkInterval) == 0) && (time > 0) && reduceFlySize ) { if ( ((time % (checkInterval*10)) != 0) ) { if ( numOldSpiders > 0 ) { efraction = efraction / (double)numOldSpiders; if ( numOldSpiders > (v.size()/2) ) { if ( efraction > 1.5 ) { rfly *= 0.80; } else if ( efraction > 1.2 ) { rflyMax = rfly; rfly *= 0.9; } else if ( efraction > 0.9 ) { rfly *= 0.95; } else if ( efraction > 0.6 ) { rfly *= 0.995; } else if ( efraction > 0.4 ) { rfly *= 0.999; } else if ( efraction < 0.3 ) { rfly = rflyMax; } // save them! } else { rfly = rflyMax; } // post mass extinction summer! } } else { rfly = rflyMax; } // summer's here, and the flies are fat! System.out.println( efraction + " Fly size: " + rfly ); } } /* keep track of element containing display spider ID */ if ( v.size() > 0 ) { boolean found = false; for ( n = 0; n < v.size(); n++ ) { spider = (Spider)v.elementAt(n); if ( spider.uniqueID == selectedDisplayID ) { selectedDisplayElement = n; found = true; break; } } /* if ID not found in vector element list, seleect last element + ID */ if (!found) { selectedDisplayElement = v.size() - 1; spider = (Spider)v.elementAt(selectedDisplayElement); selectedDisplayID = spider.uniqueID; } } /* rolling graph display data */ spider = (Spider)v.elementAt(selectedDisplayElement); double scaler = 50.0; displayStream[0] = spider.energystore / scaler; displayStream[1] = spider.webstart / scaler; displayStream[2] = spider.webstop / scaler; if ( spider.busy ) { displayStream[4] = 0; } else { displayStream[4] = -100; } spider = (Spider)v.elementAt(selectedDisplayElement); displayString[0] = "ID: " + Integer.toString(spider.uniqueID); displayString[1] = "type: " + Integer.toString(spider.webtype); displayString[2] = "age: " + Integer.toString(spider.age); displayString[3] = "obsv I%: " + Integer.toString(spider.observedIdleness() ); displayString[4] = "calc I%: " + Integer.toString(spider.idleness() ); displayString[5] = "L = " + Integer.toString((int)spider.perimeterMove[0] ); displayString[6] = "fly: " + Integer.toString( (int)(100.0 * rfly) ); displayString[7] = "T " + Integer.toString( time );; displayString[8] = " "; displayString[9] = " "; time++; } /* Choice button actions */ public boolean doChoiceAction( int choice ) { Spider spider; spider = (Spider)v.elementAt( selectedDisplayElement ); if ( choice == 0 ) { // increase fly size rfly = rfly * 1.025; System.out.println("fly size= "+rfly); } else if ( choice == 1 ) { // decrease fly size rfly = rfly * 0.975; System.out.println("fly size= "+rfly); } else if ( choice == 2) { // increase web strength spider.yarncost += 0.05; } else if ( choice == 3 ) { // decrease web strength spider.yarncost -= 0.05; if (spider.yarncost < 0.1) spider.yarncost = 0.1; } else if ( choice == 4) { // increase param[2] spider.perimeterMove[2] += 3; } else if ( choice == 5) { // decrease .. spider.perimeterMove[2] -= 3; } else if ( choice == 6) { // increase .. 3 spider.perimeterMove[3] += 3; } else if ( choice == 7) { // decrease .. 3 spider.perimeterMove[3] -= 3; } else if ( choice == 8) { // decrease .. 3 if ( numSpidersSeen == 1 ) { numSpidersSeen = 9; } else { numSpidersSeen = 1; } } System.out.println( "Choice " + choice ); return( false ); } /* find spider ID associated with vector element number */ public int findID( int element ) { Spider spider; int id = v.size()-1; if ( element < v.size() ) { spider = (Spider)v.elementAt( element ); id = spider.uniqueID; } return( id ); } } /************ Draw the spiders webs ******************************/ class WebCanvas extends Canvas { Dimension offDimension; Image offImage; Graphics offGraphics; Field field; // Constructor allows access to Field objects by this class public WebCanvas( Field f ) { super(); field = f; this.setBackground( Color.black ); } public void stop() { offGraphics = null; offImage = null; } public boolean handleEvent( Event ev ) { int xn, yn, element, id; if (ev.id == Event.MOUSE_UP ) { xn = ev.x / (int)(offDimension.width/3.0); yn = ev.y / (int)(offDimension.height/3.0); element = yn * 3 + xn; if ( element < 9 ) { field.selectedDisplayElement = element; id = field.findID( element ); field.selectedDisplayID = id; } } return true; } public void redraw() { repaint(); } // update calls paint(), otherwise clears the screen. public void update(Graphics g) { paint(g); } public void paint(Graphics g) { double x, y; Dimension d = size(); Spider s, spider; boolean select; //Create the offscreen graphics context, if no good one exists. if ( (offGraphics == null) || (d.width != offDimension.width) || (d.height != offDimension.height) ) { offDimension = d; System.out.println( "Offdimension h/w: " + offDimension.width + " "+ offDimension.height); offImage = createImage(d.width*2, d.height); offGraphics = offImage.getGraphics(); offGraphics.setPaintMode(); offGraphics.setColor(Color.darkGray); offGraphics.fillRect( 0, 0, offDimension.width, offDimension.height ); } else if (field.inited) { if ( field.numSpidersSeen == 1 ) { select=false; spider = (Spider)field.v.elementAt(field.selectedDisplayElement); spider.paintWeb( select, offGraphics, 0, 0, offDimension.width, offDimension.height ); } else if ( field.numSpidersSeen == 9 ) { for ( int n = 0; n < 9; n++ ) { if ( n == field.selectedDisplayElement ) select = true; else select = false; spider = (Spider)field.v.elementAt(n); y = ( offDimension.height/3.0 ) * (double)(n/3); x = ( offDimension.width/3.0 ) * (double)(n%3); spider.paintWeb( select, offGraphics, x, y, offDimension.width/3.0, offDimension.height/3.0 ); } } } // Paint the web onto the screen. g.drawImage(offImage, 0, 0, this); } } /*********** moving graph canvas *****************************************/ class GraphCanvas extends Canvas { Dimension fielddimension; Image fieldImage; Graphics fieldGraphics; Field field; int nstreams = 5; int lasty[] = new int[nstreams]; boolean started; int textwidth=70; // Constructor allows access to Field objects by this class public GraphCanvas( Field f ) { super(); field = f; for ( int n = 0; n < nstreams; n++ ) { lasty[n] = -65001; } started = false; } public void stop() { fieldGraphics = null; fieldImage = null; } public void redraw() { repaint(); } // update calls paint(), otherwise clears the screen. public void update(Graphics g) { paint(g); } public void paint(Graphics g) { int n; Dimension d = size(); int graph_height = 100; //Create the offscreen graphics context, if no good one exists. if ( (fieldGraphics == null) ) { fieldImage = createImage(d.width, 100); fieldGraphics = fieldImage.getGraphics(); // System.out.println( "GraphCanvas setup" ); fieldGraphics.setColor(Color.black); fieldGraphics.fillRect(0, 0, d.width, graph_height); } if ( started && field.inited ) { /* move image 1 pixel leftward */ fieldGraphics.setPaintMode(); fieldGraphics.copyArea(1,0, d.width-textwidth, graph_height-1, -1, 0 ); /* rub out unmoved vertical line */ fieldGraphics.setColor(Color.black); // busy if ( field.displayStream[nstreams-1] == -100 ) fieldGraphics.setColor(Color.white); // idle fieldGraphics.drawLine( d.width-textwidth, 0, d.width-textwidth, 100 ); /* do the data streams */ for ( n = nstreams-1; n >= 0; n-- ) { fieldGraphics.setColor(Color.orange); if ( n==0 ) fieldGraphics.setColor(Color.red); if ( n==1 ) fieldGraphics.setColor(Color.blue); if ( n==2 ) fieldGraphics.setColor(Color.green); if ( n==3 ) fieldGraphics.setColor(Color.orange); if ( n==4 ) fieldGraphics.setColor(Color.yellow); fieldGraphics.drawLine( d.width-textwidth-1, 100-lasty[n], d.width-textwidth, 100-(int)(field.displayStream[n]+0.5) ); } fieldGraphics.setColor(Color.cyan); fieldGraphics.fillRect(d.width-textwidth+1, 0, d.width, graph_height); fieldGraphics.setColor(Color.black); for ( n = 0; n < 10; n++ ) { fieldGraphics.drawString( field.displayString[n], d.width-textwidth+3 , 12*n + 12); } //Paint the image onto the screen. g.drawImage(fieldImage, 0, 0, this); } else { started = true; fieldGraphics.setColor(Color.black); fieldGraphics.fillRect(0, 0, d.width, graph_height); } for ( n = 0; n < nstreams; n++ ) lasty[n] = (int)(field.displayStream[n]+0.5); } }