/* langevinSpin.java do calculation between animation frames The applet is type 'langevinSpin'. makes calls to a simulation of type langevinSim the results for each time step are in a var of type langevinSimResult Barry Isralewitz 2002-Jan-18 */ import java.awt.*; import java.awt.geom.*; import java.applet.*; import java.text.*; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import langevinSim; import langevinSimResult; import cubbyHole; public class langevinSpin extends Applet implements ActionListener,Runnable { //method defined below //the simulation object private langevinSim theSim; //numbers we will pass to the simulation object private double number1; private double number3; //buttons private Button button_run; private Button button_pause; private Button button_restart; private Button button_reset; //text fields private TextField textField_C_units; private TextField textField_Fps; private TextField textField_totalRuns; private TextField textField_stepsPerRun; private TextField textField_R_rotor; private TextField textField_R; private TextField textField_R_arg210; private TextField textField_R_pr; private TextField textField_pH_A; private TextField textField_pH_B; private TextField textField_psi; private TextField textField_phi_A; private TextField textField_phi_B; private TextField textField_pK_A; private TextField textField_D_p; private TextField textField_D_r; private TextField textField_eps_stator; private TextField textField_lambda; private TextField textField_tau; private NumberFormat myFormat = NumberFormat.getNumberInstance() ; private cubbyHole cubby; private MediaTracker tracker; //boolean simStarted = false; private int frameNumber = -1; private int fps; // inverse of delay, but need to memorize user setting private int delay; private int stepsPerRun; private int totalRuns; Thread animatorThread; boolean frozen = false; boolean restarted = false; boolean backgroundDrawn = false; boolean paintedOnce = false; //panel for buttons/type-in field //panel for buttons/type-in fieldss Panel controlPanel; int fieldWidth = 10; //vars to store graphics display for double-buffering private Graphics bg=null; //to handle double-buffering animation, null to signal not set yet private Graphics cg; //to handle double-buffering animation Image buffered_image, buffered_copy; //stores the off-screen images //some vars for calculating display private int bufSizeX = 640; private int bufSizeY = 372; private int prevGraphX; private int prevGraphY; private int r = 100; private int cx = 185; // center of that circle private int cy = 127; private int statorX = 85; private int statorY = 271; private int statorWidth = 200; private int statorHeight = 100; private double screenTheta = 0; // so 0 degrees is at 'south' position private int screenThetaDegrees = 0; // we'll have to use integer version of angle several times private double d=0; private double h1Length = 0.9 * r; private double h23Length = 0.7 * r; private double h23Angle = (20.0/180.0)* Math.PI; private int graphPosX = 325; private int graphPosY = 10; private int graphHeight= 200; private int graphWidth =280; private int xMargin=3; private int yMargin=3; private int graphYOrigin= graphPosY + yMargin + ( (graphHeight - yMargin) /2 ); private double xRatio; private double yRatio; //this method is always 1 frame behind, do it real way later with real extra buffer... //array of pictures to show state diagram private Image[] statePicture; private Image lipidUpPicture, lipidDownPicture; //constructor is called at init for applets public void init () { //set cubby contents to signal 'sim not run yet' cubby = new cubbyHole (new langevinSimResult(-1,0,0,0,"") ); String str; //dummy string to examine parameters int fps = 50; //How many milliseconds between frames? str = getParameter("fps"); try { if (str != null) { fps = Integer.parseInt(str); } } catch (Exception e) {} //default is 50 fps delay = (fps > 0) ? (1000 / fps) : 20; //copy in the parameters set by the HTML calling this applet.. stepsPerRun = (int) new Double(getParameter("number1")).doubleValue(); totalRuns = (int) new Double(getParameter("number3")).doubleValue(); //tell the programmer about this //make the grid window; //aGridWindow = new GridWindow(); // for graphics, set inital X,Y plot position; sjhould do this via method, same code in paint // with actual values.. xRatio = (0.0+ graphWidth - xMargin)/(totalRuns*stepsPerRun); yRatio = (graphHeight - yMargin)/10; //System.out.println ("calc xratio, totalRuns=" + totalRuns + " stepsPerRun= "+stepsPerRun+ " xRatio= "+xRatio); prevGraphX= (int) (graphPosX+xMargin-(xRatio*(0))); prevGraphY= (int) ( graphYOrigin-(yRatio* 0)) ; //load in graphics statePicture = new Image[4]; statePicture[0] = getImage(getCodeBase(), "state-00-pink.gif"); //state 1 statePicture[3] = getImage(getCodeBase(), "state-01-pink.gif"); //state 4 statePicture[2] = getImage(getCodeBase(), "state-11-pink.gif"); //state 3 statePicture[1] = getImage(getCodeBase(), "state-10-pink.gif"); //state 2 lipidUpPicture= getImage(getCodeBase(), "lipid-up.gif"); lipidDownPicture= getImage(getCodeBase(), "lipid-down.gif"); // yup, it arbitray, not binary(state -1 ) //switched pcitures 3 and 1 with Alek to reflect a possible stator polariry solution. //also switched left/right in stator picture. //track the images, assign them to tracker ID 0 tracker = new MediaTracker(this); for (int i=0; i<=3; i++) { tracker.addImage(statePicture[i],0); } //set vars to initialize a new run //normally, get these from pramaters int timestep=0; double theta=0.e0; int pie=0; int state=1; long seed=67657; int C_units=12; double dt=1.e-8, dx=1.e0; double D_r = 2.e4, D_p = 9.3e9, R=0.5e0, R_rotor=5.e0, R_arg210=5.4e0; double lambda=1.e0/1.1e0, eps_stator =10.e0, R_pr=5.e0; double pH_A = 7.0e0, pH_B = 8.4e0, pK_A = 7.0e0; double phi_A = 2.3e0, phi_B = 2.3e0, psi = 5.6e0; double tau = 41e0/4.1e0; //create a new sim object with this info. theSim = new langevinSim (timestep, theta, pie, state, seed, C_units, dt, dx, D_r, D_p, R, R_rotor, R_arg210, lambda, eps_stator, R_pr, pH_A, pH_B, pK_A, phi_A, phi_B, psi, tau); //make a place at the bottom of the applet for a control panel setLayout(new BorderLayout(0,315)); //controlPanel = new Panel( new FlowLayout() ); controlPanel = new Panel( new GridLayout(0,4) ); add ("South", controlPanel); //add a label as spacer //controlPanel.add(new Label("", Label.RIGHT)); //now add some buttons button_run = new Button("Run"); controlPanel.add(button_run); button_run.addActionListener(this); //controlPanel.add(new Label("", Label.RIGHT)); button_pause = new Button("Pause"); controlPanel.add(button_pause); button_pause.addActionListener(this); button_restart = new Button("Restart"); controlPanel.add(button_restart); button_restart.addActionListener(this); button_reset = new Button("Reset Vars."); controlPanel.add(button_reset); button_reset.addActionListener(this); //and add some text fields, with adjacent labels to explain them controlPanel.setFont(new Font("Helvetica", Font.PLAIN, 12)); controlPanel.add(new Label("steps/frame", Label.RIGHT)); textField_stepsPerRun= new TextField(""+stepsPerRun,fieldWidth); controlPanel.add(textField_stepsPerRun); textField_stepsPerRun.addActionListener(this); //thanks to using the cubbyHole, exactly 1 run / frame // easier to explain to user by calling 'em 'frames'. controlPanel.add(new Label("total frames", Label.RIGHT)); textField_totalRuns= new TextField(""+totalRuns,fieldWidth); controlPanel.add(textField_totalRuns); textField_totalRuns.addActionListener(this); controlPanel.add(new Label("fps", Label.RIGHT)); textField_Fps= new TextField(""+fps,fieldWidth); controlPanel.add(textField_Fps); textField_Fps.addActionListener(this); controlPanel.add(new Label("pKa, rotor sites, Asp61", Label.RIGHT)); textField_pK_A= new TextField(""+pK_A,fieldWidth); controlPanel.add(textField_pK_A); textField_pK_A.addActionListener(this); controlPanel.add(new Label("diel. const of channel", Label.RIGHT)); textField_eps_stator= new TextField(""+eps_stator,fieldWidth); controlPanel.add(textField_eps_stator); textField_eps_stator.addActionListener(this); controlPanel.add(new Label("load torque", Label.RIGHT)); textField_tau= new TextField(""+tau,fieldWidth); controlPanel.add(textField_tau); textField_tau.addActionListener(this); controlPanel.add(new Label("number of c subunits", Label.RIGHT) ); textField_C_units = new TextField(""+theSim.C_units,fieldWidth); controlPanel.add(textField_C_units); textField_C_units.addActionListener(this); controlPanel.add(new Label("radius of rotor (nm)", Label.RIGHT)); textField_R_rotor= new TextField(""+R_rotor,fieldWidth); controlPanel.add(textField_R_rotor); textField_R_rotor.addActionListener(this); controlPanel.add(new Label("radius. prot. chnls", Label.RIGHT)); textField_R= new TextField(""+R,fieldWidth); controlPanel.add(textField_R); textField_R.addActionListener(this); controlPanel.add(new Label("dist. to Arg210 (nm)", Label.RIGHT)); textField_R_arg210= new TextField(""+R_arg210,fieldWidth); controlPanel.add(textField_R_arg210); textField_R_arg210.addActionListener(this); controlPanel.add(new Label("dist to Asp61 prot(nm)", Label.RIGHT)); textField_R_pr= new TextField(""+R_pr,fieldWidth); controlPanel.add(textField_R_pr); textField_R_pr.addActionListener(this); controlPanel.add(new Label("pH acidic res. (peri.)", Label.RIGHT)); textField_pH_A= new TextField(""+pH_A,fieldWidth); controlPanel.add(textField_pH_A); textField_pH_A.addActionListener(this); controlPanel.add(new Label("pH basic res (cyto.)", Label.RIGHT)); textField_pH_B= new TextField(""+pH_B,fieldWidth); controlPanel.add(textField_pH_B); textField_pH_B.addActionListener(this); controlPanel.add(new Label("membrane pot'l (kT)", Label.RIGHT)); textField_psi= new TextField(""+psi,fieldWidth); controlPanel.add(textField_psi); textField_psi.addActionListener(this); controlPanel.add(new Label("surf. pot. drop, acidic", Label.RIGHT)); textField_phi_A= new TextField(""+phi_A,fieldWidth); controlPanel.add(textField_phi_A); textField_phi_A.addActionListener(this); controlPanel.add(new Label("surf. pot. drop, basic", Label.RIGHT)); textField_phi_B= new TextField(""+phi_B,fieldWidth); controlPanel.add(textField_phi_B); textField_phi_B.addActionListener(this); controlPanel.add(new Label("prot. diffusion coeff.", Label.RIGHT)); textField_D_p= new TextField(""+D_p,fieldWidth); controlPanel.add(textField_D_p); textField_D_p.addActionListener(this); controlPanel.add(new Label("rotary diffusion coeff.", Label.RIGHT)); textField_D_r= new TextField(""+D_r,fieldWidth); controlPanel.add(textField_D_r); textField_D_r.addActionListener(this); controlPanel.add(new Label("shld length chnl. chgs", Label.RIGHT)); textField_lambda= new TextField(""+lambda,fieldWidth); controlPanel.add(textField_lambda); textField_lambda.addActionListener(this); } public void start() { if (frozen) { //Do nothing. The user has requested that we //stop changing the image. } else { //Start animating! if (animatorThread == null) { animatorThread = new Thread(this); } animatorThread.start(); } } public void stop() { //Stop the animating thread. animatorThread = null; } public boolean mouseDown(Event e, int x, int y) { if (frozen) { frozen = false; start(); } else { frozen = true; stop(); } return true; } public void run() { langevinSimResult currentResult; //used only to check if was error message when run //first, wait for download.. try { //Start downloading the images. Wait until they're loaded. tracker.waitForAll(); } catch (InterruptedException e) {} //Just to be nice, lower this thread's priority //so it can't interfere with other processing going on. //Thread.currentThread().setPriority(Thread.MIN_PRIORITY); //Remember the starting time. long startTime = System.currentTimeMillis(); //Remember which thread we are. Thread currentThread = Thread.currentThread(); //System.out.println("In run(), delay= "+delay+" stepsPerRun (tsteps/frame)=" + stepsPerRun+ "totalRuns(frames)"+totalRuns); //draw background if this is the first time through if (bg == null) { //strictly, this should be in update method, so we'd know size for certain. buffered_image = createImage(bufSizeX,bufSizeY); buffered_copy = createImage(bufSizeX,bufSizeY); bg = buffered_image.getGraphics(); System.out.println("set bg.."); } //old starting status report //bg.setFont(new Font("Times", Font.BOLD, 18)); //bg.drawString("stepsPerRun(tsteps/rep)= >" + stepsPerRun+"<." , 50, 25); //bg.drawString("totalRuns(reps)= >" + totalRuns+"<." , 50, 45); //bg.translate(getInsets().left, getInsets().top); if ( (backgroundDrawn == false) || (restarted == true) ) { backgroundDrawn = true; drawBackground(); } //This is the animation loop. //while ((currentThread == animatorThread) && (frameNumber < totalRuns)) { while (currentThread == animatorThread ) { if ((frameNumber < totalRuns) && (restarted == false)) { //Advance the animation frame. frameNumber++; //System.out.println("In run(), frameNumber= "+frameNumber+ " -- starting runSteps"); // now, actually run the simulation a few steps // we could be clever and make this a differerent thread // and share data via get/put to a cubbyHole, but this //should be enough for now currentResult = theSim.runSteps(stepsPerRun); if (currentResult.errorMessage != "") { //somehow, get this painted too System.out.println("Stopped in loop, error message= "+currentResult.errorMessage); repaint(); frozen = true; stop(); } cubby.put( currentResult ); //System.out.println("In run(), frameNumber= "+frameNumber+ " -- finished put"); //System.out.println("In run(), frameNumber= "+frameNumber+" -- finished runSteps, now call repaint..."); //Display it. repaint(); //Delay depending on how far we are behind. try { startTime += delay; Thread.sleep(Math.max(0, startTime-System.currentTimeMillis())); } catch (InterruptedException e) { break; } //System.out.println("In run(), frameNumber= "+frameNumber+ " -- finished repaint"); } if (restarted == true) { theSim.doReset(0,0,0,1); frameNumber = -1; restarted = false; delay = (fps > 0) ? (1000 / fps) : 20; xRatio = (0.0+ graphWidth - xMargin)/(totalRuns*stepsPerRun); yRatio = (graphHeight - yMargin)/10; //System.out.println ("calc xratio, totalRuns=" + totalRuns + " stepsPerRun= "+stepsPerRun+ " xRatio= "+xRatio); prevGraphX= (int) (graphPosX+xMargin-(xRatio*(0))); prevGraphY= (int) ( graphYOrigin-(yRatio* 0)) ; drawBackground(); restarted = false; //repaint(); //System.out.println("Restart pressed... theSim.timestep= "+theSim.timestep); } } //turn off 'Run" button //button_run.setEnabled(false); } public void update (Graphics g) { paint(g); } public void paint(Graphics g) { Dimension d =size(); //System.out.println("In paint, tracker.checkAll()= "+tracker.checkAll()); if (!tracker.checkAll()) { //System.out.println("In paint, in clear loop,tracker.checkAll()= "+tracker.checkAll()); g.clearRect(0, 0, d.width, d.height); g.drawString("Please wait, loading graphics...", 0, -100+ d.height/2); } else { //langevinSimResult theResult = cubby.get(); langevinSimResult theResult = cubby.peek(); //if simulation hasn't started, don't do anything // this has nothing to do with -1 that initializes frameNumber // If decide to be frozen on start, // maybe display "Push to start", or initial state, here if (theResult.timestep == -1) { System.out.println("In paint, theResult.timestep == -1, exiting"); return; } //update the graphics to reflect theResult // we want theta to point just to right of south (down) on the screen, so use screenTheta for circular rotor cartoon // but the real value is still theResult.theta, use for graphing //for stator, put in offset as well double offsetTheta = (theResult.theta) + (theSim.Rotor_step/2); //double offsetTheta = theResult.theta + (theSim.Rotor_step/2); screenTheta = offsetTheta - (Math.PI / 2) ; screenThetaDegrees= (int) (screenTheta * 180.0 / Math.PI); //print diagnostics //System.out.println("In paint, timestep= " + theResult.timestep+ " theta= "+ theResult.theta + "screenThetaDegrees= " + screenThetaDegrees + "pie=" + theResult.pie + "state= "+theResult.state + " offsetTheta= "+ offsetTheta); //theSim.printState(); //+x is right, +y is down in graphics field //int dx1 = (int)(r * Math.cos(screenTheta)); //int dy1 = (int)(r * Math.sin(screenTheta)); //for testing, we'll draw a pacman(R), jaw open 0.17 radians,about 10 degrees) //int dx2 = (int)(r * Math.cos(0.17+ screenTheta)); //int dy2 = (int)(r * Math.sin(0.17+ screenTheta)); //clear this drawing area to the saved IMAGe cg.drawImage(buffered_image,0,0,null); //cg.drawImage(buffered_image,0,0,this); //add some status text cg.setColor(Color.white); cg.setFont(new Font("Helvetica", Font.PLAIN, 14)); cg.drawString("timestep= " + theResult.timestep, 8, 20 ); cg.drawString("theta= " + myFormat.format(theResult.theta), 8, 35); //cg.drawString("pie= " + theResult.pie, 35, 60); //cg.drawString("state= " + theResult.state, 65, 75); //bg.translate(getInsets().left, getInsets().top); //uses degress for angle units //trivial if we could use Java2D stuff... //GradientPaint grad0 = new GradientPaint(0,16,Color.red, 0,24,Color.blue); //Graphics2D cg2 = (Graphics2D) cg; //cg2.setPaint(grad0); //Ellipse2D obj3 = new Ellipse2D.Double(14,0,60,60); //cg2.fill(obj3); //draw disc cg.setColor(new Color(171,211,175)); cg.fillOval(cx-r, cy-r, 2*r,2*r); //shade the circle double px1,py1,px2,py2,cosTheta,sinTheta,circX,circY; int col,x1t,y1t,x2t,y2t; int r2 = r*r; double colorRatio = 2 * r; cosTheta = Math.cos(offsetTheta); sinTheta = Math.sin(offsetTheta); //cosTheta = Math.cos(offsetTheta+theSim.Rotor_step/2 ); //sinTheta = Math.sin(offsetTheta+theSim.Rotor_step/2 ); /* //works fine, but too slow for IE on 200MHz PC's for ( circY = -r; circY <= r; circY = circY + 0.5) { col = (int)( (circY +r) / colorRatio * 255.0); cg.setColor(new Color(col,255,col) ); circX = ( Math.sqrt (r2 - circY * circY)); //transform the coords px1 = -circX; py1 = circY; px2 = circX; py2 = circY; x1t = (int) (px1* cosTheta + py1 * sinTheta); y1t = (int) (-px1*sinTheta + py1 * cosTheta); x2t = (int) (px2* cosTheta + py2 * sinTheta); y2t = (int) (-px2*sinTheta + py2 * cosTheta); cg.drawLine (cx+x1t,cy+y1t,cx+x2t, cy+y2t); //draw another line right below this to fill in spaces left by limitations //created by specifying lines in integers cg.drawLine (cx+x1t,cy+1+y1t,cx+x2t, cy+1+y2t); } */ for ( circY = -r; circY <= r; circY = circY + 20) { col = (int)( (circY +r) / colorRatio * 255.0); cg.setColor(new Color(col,255,col) ); circX = ( Math.sqrt (r2 - circY * circY)); //transform the coords for (int incr =0; incr < 2; incr++) { px1 = -circX; py1 = circY+incr; px2 = circX; py2 = circY+incr; x1t = (int) (px1* cosTheta + py1 * sinTheta); y1t = (int) (-px1*sinTheta + py1 * cosTheta); x2t = (int) (px2* cosTheta + py2 * sinTheta); y2t = (int) (-px2*sinTheta + py2 * cosTheta); cg.drawLine (cx+x1t,cy+y1t,cx+x2t, cy+y2t); } } //draw circumfrence //cg.setColor(new Color(171,211,175)); cg.setColor(Color.black); cg.drawOval(cx-r, cy-r, 2*r,2*r); cg.drawOval(cx-r, cy-r+1, 2*r,2*r); //draw a dot in the middle for the arrow to spin on cg.setColor(Color.black); cg.fillOval(cx-4, cy-4, 8, 8); //calcs for arrow // note that y increases as you go 'south' on the screen, i.e. quadrant IV int h1x = (int) (cx + (h1Length * Math.cos(screenTheta)) ); int h1y = (int) (cy - (h1Length * Math.sin(screenTheta)) ); int h2x = (int) (cx + (h23Length * Math.cos(screenTheta + h23Angle) ) ); int h2y = (int) (cy - (h23Length * Math.sin(screenTheta + h23Angle) ) ); int h3x = (int) (cx + (h23Length * Math.cos(screenTheta - h23Angle) ) ); int h3y = (int) (cy - (h23Length * Math.sin(screenTheta - h23Angle) ) ); //System.out.println("In paint, theResult.theta= "+theResult.theta+" h1x=" + h1x+ " h1y= "+h1y+" h2x= "+h2x+" h2y= "+h2y+ " h23Angle="+h23Angle+" theResult.theta+h23Angle= "+(theResult.theta+h23Angle)); //draw the arrow cg.setColor(Color.black); cg.drawLine(cx,cy,h1x,h1y); cg.drawLine(h1x,h1y,h2x,h2y); cg.drawLine(h1x,h1y,h3x,h3y); cg.setColor(Color.red); int dotx,doty; double ang; double slice = 2.0 * Math.PI / theSim.C_units; //double slice = 2.0 * Math.PI / 12.0; cg.setColor(Color.black); for (int dot =0; dot 0 ) { cg.setColor(neg_color); cg.fillOval ( (int)( -backDotSizeHalf+ statorXratio * (prot_pos- 2* theSim.Rotor_step)) + statorHalf, -backDotSizeHalf + statorHalfHeight,backDotSize,backDotSize); cg.setColor(Color.black); cg.fillOval ( (int)( -dotSizeHalf+ statorXratio * (prot_pos- 2* theSim.Rotor_step)) + statorHalf, -dotSizeHalf + statorHalfHeight,dotSize,dotSize); //draw background dot cg.setColor(neg_color); cg.fillOval ( (int)( -backDotSizeHalf + statorXratio * (prot_pos- theSim.Rotor_step)) + statorHalf, -backDotSizeHalf + statorHalfHeight,backDotSize,backDotSize); //outline the background dot //cg.setColor(Color.black); //cg.drawOval ( (int)( -backDotSizeHalf + statorXratio * (prot_pos- theSim.Rotor_step)) + statorHalf, -backDotSizeHalf + statorHalfHeight,backDotSize,backDotSize); //draw dot cg.setColor(left); cg.fillOval ( (int)( -dotSizeHalf + statorXratio * (prot_pos- theSim.Rotor_step)) + statorHalf, -dotSizeHalf + statorHalfHeight,dotSize,dotSize); cg.setColor(neg_color); cg.fillOval ( (int)( -backDotSizeHalf + statorXratio * prot_pos + statorHalf), -backDotSizeHalf + statorHalfHeight, backDotSize,backDotSize); cg.setColor(right); cg.fillOval ( (int)( -dotSizeHalf + statorXratio * prot_pos + statorHalf), -dotSizeHalf + statorHalfHeight, dotSize,dotSize); cg.setColor (neg_color); cg.fillOval ( (int)( -backDotSizeHalf + statorXratio * (prot_pos+ theSim.Rotor_step)) + statorHalf, -backDotSizeHalf+ statorHalfHeight,backDotSize,backDotSize); cg.setColor (Color.black); cg.fillOval ( (int)( -dotSizeHalf + statorXratio * (prot_pos+ theSim.Rotor_step)) + statorHalf, -dotSizeHalf+ statorHalfHeight,dotSize,dotSize); //add text cg.setColor(Color.black); cg.drawString ( ""+thetaToSiteNum(offsetTheta, -1), (int) (statorXratio * (prot_pos- 2 * theSim.Rotor_step)) + statorHalf +xTextOff, statorHalfHeight + yTextOff); cg.drawString ( ""+thetaToSiteNum(offsetTheta, 0), (int) (statorXratio * (prot_pos- theSim.Rotor_step)) + statorHalf +xTextOff, statorHalfHeight + yTextOff); cg.drawString (""+ thetaToSiteNum(offsetTheta,+1), (int) (statorXratio * (prot_pos)) + statorHalf - xTextOff, statorHalfHeight + yTextOff) ; cg.drawString ( ""+thetaToSiteNum(offsetTheta,+2), (int) (statorXratio * (prot_pos+ theSim.Rotor_step)) + statorHalf - xTextOff, statorHalfHeight + yTextOff); } else { cg.setColor(neg_color); cg.fillOval ( (int)( -backDotSizeHalf+ statorXratio * (prot_pos- theSim.Rotor_step)) + statorHalf, -backDotSizeHalf+ statorHalfHeight,backDotSize,backDotSize); cg.setColor(Color.black); cg.fillOval ( (int)( -dotSizeHalf+ statorXratio * (prot_pos- theSim.Rotor_step)) + statorHalf, -dotSizeHalf+ statorHalfHeight,dotSize,dotSize); cg.setColor(neg_color); cg.fillOval ( (int)( -backDotSizeHalf+ statorXratio * prot_pos + statorHalf), -backDotSizeHalf+ statorHalfHeight, backDotSize,backDotSize); cg.setColor(left); cg.fillOval ( (int)( -dotSizeHalf+ statorXratio * prot_pos + statorHalf), -dotSizeHalf+ statorHalfHeight, dotSize,dotSize); cg.setColor(neg_color); cg.fillOval ( (int)( -backDotSizeHalf+ statorXratio * (prot_pos+ theSim.Rotor_step)) + statorHalf, -backDotSizeHalf+ statorHalfHeight,backDotSize,backDotSize); cg.setColor(right); cg.fillOval ( (int)( -dotSizeHalf+ statorXratio * (prot_pos+ theSim.Rotor_step)) + statorHalf, -dotSizeHalf+ statorHalfHeight,dotSize,dotSize); cg.setColor(neg_color); cg.fillOval ( (int)( -backDotSizeHalf + statorXratio * (prot_pos+ 2* theSim.Rotor_step)) + statorHalf, -backDotSizeHalf + statorHalfHeight,backDotSize,backDotSize); cg.setColor(Color.black); cg.fillOval ( (int)( -dotSizeHalf + statorXratio * (prot_pos+ 2* theSim.Rotor_step)) + statorHalf, -dotSizeHalf + statorHalfHeight,dotSize,dotSize); //add text cg.setColor(Color.black); cg.drawString ( ""+thetaToSiteNum(offsetTheta, -1), (int) (statorXratio * (prot_pos- theSim.Rotor_step)) + statorHalf - xTextOff, statorHalfHeight + yTextOff); cg.drawString (""+ thetaToSiteNum(offsetTheta,0), (int) (statorXratio * (prot_pos)) + statorHalf +xTextOff , statorHalfHeight + yTextOff) ; cg.drawString ( ""+thetaToSiteNum(offsetTheta,+1), (int) (statorXratio * (prot_pos+ theSim.Rotor_step)) + statorHalf + xTextOff, statorHalfHeight + yTextOff); cg.drawString ( ""+thetaToSiteNum(offsetTheta,+2), (int) (statorXratio * (prot_pos+ 2* theSim.Rotor_step)) + statorHalf +xTextOff , statorHalfHeight + yTextOff); } //draw some phospholipids to make a membrane int leftLipids = 4; int rightLipids =6; int horzMargin = 2; int vertMargin = 3; int lipLeftUpX = statorX-horzMargin - (lipidUpPicture.getWidth(this) * leftLipids); int lipUpY = statorY+vertMargin; int lipDownY = statorY + statorHeight - vertMargin - (lipidUpPicture.getHeight(this)); int lipLeftDownX = statorX-horzMargin - (lipidUpPicture.getWidth(this) * leftLipids); int lipRightUpX= statorX + horzMargin + statorWidth ; int lipRightDownX = statorX + horzMargin + statorWidth ; for (int l = 0; l < leftLipids; l++) { cg.drawImage(lipidUpPicture, lipLeftUpX + (l * lipidUpPicture.getWidth(this)), lipUpY, this); cg.drawImage(lipidDownPicture, lipLeftDownX + (l * lipidUpPicture.getWidth(this)) , lipDownY, this); //System.out.println("lipUpY="+lipUpY+" lipRightUpX="+lipRightUpX+" Xpos="+ lipLeftUpX + l * lipidUpPicture.getWidth(this) +" lipUpY="+ (lipUpY + l * lipidUpPicture.getHeight(this) )); } for (int l = 0; l < rightLipids; l++) { cg.drawImage(lipidUpPicture, lipRightUpX + l * lipidUpPicture.getWidth(this), lipUpY , this); cg.drawImage(lipidDownPicture, lipRightDownX + l * lipidUpPicture.getWidth(this), lipDownY , this); } //System.out.println("lipUpY="+lipUpY+" lipRightUpX="+lipRightUpX+" Xpos="+ lipLeftUpX + l * lipidUpPicture.getWidth(this) +" lipUpY="+ (lipUpY + l * lipidUpPicture.getHeight(this) )); //draw the graph (can use a special graphic buffer for this, then add on to it.) //Can just use bg. But maybe use special one later. //Draw dots now, lines later... //this method is always 1 frame behind, do it real way later with real extra buffer... int graphX= (int) (xMargin+ graphPosX+(xRatio*theResult.timestep)); int graphY= (int) ( graphYOrigin - (yRatio* theResult.theta)) ; //System.out.println ("Now to draw line on bg... graphX= "+graphX+" graphY= "+ graphY + " prevGraphX= "+prevGraphX+" prevGraphY= "+prevGraphY + "xRatio= "+xRatio+ " yRatio= " + yRatio + "graphPosX=" + graphPosX + "graphPosY= "+graphPosY); bg.setColor(Color.black); bg.drawLine (prevGraphX, prevGraphY, graphX, graphY); //bg.setColor(Color.green); //bg.fillOval (graphX,(5* theResult.pie)+30, 2,2); prevGraphX = graphX; prevGraphY= graphY; //copy image onto screen //System.out.println("In paint, now to copy bg to g..."); if (theResult.errorMessage != "") { cg.setColor(new Color (200,0,0)); cg.setFont(new Font("Helvetica", Font.BOLD, 18)); cg.drawString("Simulation error:", 10,190); cg.drawString(" "+theResult.errorMessage, 10,210); cg.drawString("Press 'Restart' key...", 10,230); } //freeze if first time through if (paintedOnce == false) { System.out.println("painted Once now will be set true"); paintedOnce = true; frozen = true; stop(); } } g.drawImage(buffered_copy,0,0,null); //g.drawImage(buffered_copy,0,0,this); //System.out.println("leaving paint, timestep= "+ theResult.timestep); } public void actionPerformed (ActionEvent e ) { //could set all vars in this, but we might want to know // which field was changed System.out.println("The action command is " + e.getActionCommand() ); System.out.println("The string rep of obj is " + e.toString() ); if (e.getSource()== button_reset) { resetSimParams(); } else if (e.getSource()== button_restart) { //System.out.println("Case button_restart,The string rep of obj is " + e.toString() ); //stop(); restarted = true; theSim.step = stepsPerRun +1; theSim.doReset(0,0,0,1); frameNumber = -1; delay = (fps > 0) ? (1000 / fps) : 20; xRatio = (0.0+ graphWidth - xMargin)/(totalRuns*stepsPerRun); yRatio = (graphHeight - yMargin)/10; //System.out.println ("calc xratio, totalRuns=" + totalRuns + " stepsPerRun= "+stepsPerRun+ " xRatio= "+x Ratio); prevGraphX= (int) (graphPosX+xMargin-(xRatio*(0))); prevGraphY= (int) ( graphYOrigin-(yRatio* 0)) ; drawBackground(); try { Thread.sleep(500); } catch (InterruptedException ex) { } frozen = false; repaint(); //start(); } else if (e.getSource()== button_run) { //System.out.println("Case button_run,The string rep of obj is " + e.toString() ); frozen = false; start(); } else if (e.getSource()== button_pause) { //System.out.println("Case button_run,The string rep of obj is " + e.toString() ); frozen = true; stop(); } else if (e.getSource()== textField_C_units) { String text = textField_C_units.getText(); theSim.C_units = (int) new Double(text).doubleValue(); textField_C_units.selectAll(); //System.out.println("Case textField_C_units,The string rep of obj is " + e.toString() ); } else if (e.getSource() == textField_totalRuns) { String text = textField_totalRuns.getText(); //duplicates code at init, this is oddest of type-in fields... try { if (text != null) { totalRuns= Integer.parseInt(text); } } catch (Exception except) {} delay = (totalRuns> 0) ? totalRuns: 1000; //System.out.println("case textField_totalRuns, The string rep of obj is " + e.toString() ); textField_totalRuns.selectAll(); } else if (e.getSource() == textField_stepsPerRun) { String text = textField_stepsPerRun.getText(); //duplicates code at init, this is oddest of type-in fields... try { if (text != null) { stepsPerRun= Integer.parseInt(text); } } catch (Exception except) {} delay = (stepsPerRun > 0) ? stepsPerRun : 250; //System.out.println("case textField_stepsPerRun, The string rep of obj is " + e.toString() ); textField_stepsPerRun.selectAll(); } else if (e.getSource() == textField_Fps) { String text = textField_Fps.getText(); //duplicates code at init, this is oddest of type-in fields... try { if (text != null) { fps = Integer.parseInt(text); } } catch (Exception except) {} //default is 50 fps delay = (fps > 0) ? (1000 / fps) : 20; //System.out.println("case textField_Fps, The string rep of obj is " + e.toString() ); textField_Fps.selectAll(); } else if (e.getSource() == textField_R_rotor) { String text = textField_R_rotor.getText(); theSim.R_rotor = (int) new Double(text).doubleValue(); textField_R_rotor.selectAll(); //System.out.println("Case textField_R_rotor,The string rep of obj is " + e.toString() ); } else if (e.getSource() == textField_R_arg210) { String text = textField_R_arg210.getText(); theSim.R_arg210 = (int) new Double(text).doubleValue(); textField_R_arg210.selectAll(); } else if (e.getSource() == textField_R) { String text = textField_R.getText(); theSim.R = (int) new Double(text).doubleValue(); textField_R.selectAll(); } else if (e.getSource() == textField_R_pr) { String text = textField_R_pr.getText(); theSim.R_pr = (int) new Double(text).doubleValue(); textField_R_pr.selectAll(); } else if (e.getSource() == textField_pH_A) { String text = textField_pH_A.getText(); theSim.pH_A = (int) new Double(text).doubleValue(); textField_pH_A.selectAll(); } else if (e.getSource() == textField_pH_B) { String text = textField_pH_B.getText(); theSim.pH_B = (int) new Double(text).doubleValue(); textField_pH_B.selectAll(); } else if (e.getSource() == textField_psi) { String text = textField_psi.getText(); theSim.psi = (int) new Double(text).doubleValue(); textField_psi.selectAll(); } else if (e.getSource() == textField_phi_A) { String text = textField_phi_A.getText(); theSim.phi_A = (int) new Double(text).doubleValue(); textField_phi_A.selectAll(); } else if (e.getSource() == textField_phi_B) { String text = textField_phi_B.getText(); theSim.phi_B = (int) new Double(text).doubleValue(); textField_phi_B.selectAll(); } else if (e.getSource() == textField_pK_A) { String text = textField_pK_A.getText(); theSim.pK_A = (int) new Double(text).doubleValue(); System.out.println("theSim.pK_A="+theSim.pK_A); textField_pK_A.selectAll(); } else if (e.getSource() == textField_D_p) { String text = textField_D_p.getText(); theSim.D_p = (int) new Double(text).doubleValue(); textField_D_p.selectAll(); } else if (e.getSource() == textField_D_r) { String text = textField_D_r.getText(); theSim.D_r = (int) new Double(text).doubleValue(); textField_D_r.selectAll(); } else if (e.getSource() == textField_eps_stator) { String text = textField_eps_stator.getText(); theSim.eps_stator = (int) new Double(text).doubleValue(); textField_eps_stator.selectAll(); } else if (e.getSource() == textField_lambda) { String text = textField_lambda.getText(); theSim.lambda= (int) new Double(text).doubleValue(); textField_lambda.selectAll(); } else if (e.getSource() == textField_tau) { String text = textField_tau.getText(); theSim.tau= (int) new Double(text).doubleValue(); textField_tau.selectAll(); } //theSim.C_units = (int) new Double(text).doubleValue(); //textField_C_units.selectAll(); } public int thetaToSiteNum (double theta, int offset) { //convert for the 1 to C_units circular numbering of rotor cartoon //site is 0 to n-1 int site = 0; if (theta>=0) { site = (int) (theSim.C_units - 1 - ( (Math.floor (theta/theSim.Rotor_step) ) % theSim.C_units) ); //System.out.println("theta pos, site="+site); } else { site = (int) ( (Math.floor (-theta/theSim.Rotor_step)% theSim.C_units ) ) ; //System.out.println("site="+site); } site = (site + offset)% theSim.C_units ; if (site < 0 ) { site = site+ theSim.C_units; } return site + 1; } public void finalize() { ///Just in case not done automatically... bg.dispose(); cg.dispose(); buffered_copy.flush(); buffered_image.flush(); } public void resetSimParams() { theSim.C_units=12; textField_C_units.setText(""+theSim.C_units); theSim.D_r = 2.e4; textField_D_r.setText(""+theSim.D_r); theSim.D_p = 9.3e9; textField_D_p.setText(""+theSim.D_p); theSim.R=0.5e0; textField_R.setText(""+theSim.R); theSim.R_rotor=5.e0; textField_R_rotor.setText(""+theSim.R_rotor); theSim.R_arg210=5.4e0;textField_R_arg210.setText(""+theSim.R_arg210); theSim.lambda=1.e0/1.1e0;textField_lambda.setText(""+theSim.lambda); theSim.eps_stator =10.e0;textField_eps_stator.setText(""+theSim.eps_stator); theSim.R_pr=5.e0;textField_R_pr.setText(""+theSim.R_pr); theSim.pH_A = 7.0e0;textField_pH_A.setText(""+theSim.pH_A); theSim.pH_B = 8.4e0;textField_pH_B.setText(""+theSim.pH_B); theSim.pK_A = 7.0e0;textField_pK_A.setText(""+theSim.pK_A); theSim.phi_A = 2.3e0;textField_phi_A.setText(""+theSim.phi_A); theSim.phi_B = 2.3e0;textField_phi_B.setText(""+theSim.phi_B); theSim.psi = 5.6e0;textField_psi.setText(""+theSim.psi); theSim.tau = 41e0/4.1e0;textField_tau.setText(""+theSim.tau); cubby = new cubbyHole (new langevinSimResult(-1,0,0,0,"") ); } public void drawBackground() { bg.clearRect(0,0,bufSizeX,bufSizeY); System.out.println("cleared rect...."); int arcR = r + 30; //draw circle solid background //draw a curved stator double theta_3_deg = 180.0/Math.PI * theSim.theta_3; System.out.println("theta_3_deg= "+theta_3_deg); bg.setColor(new Color(123,153,123)); bg.fillArc (cx-arcR, cy-arcR, 2*arcR, 2*arcR, (int) (-90 - theta_3_deg) , (int) (2 * theta_3_deg)) ; //draw a plus sign in the stator bg.setColor (new Color (196,204,255) ); int plusSize = 8; bg.fillOval(cx - plusSize/2, (cy + r + 15) - plusSize/2, plusSize, plusSize); //System.out.println("max width= "+getMaximumSize().width+ "+max height= "+ getMaximumSize().height); //System.out.println("drawing axes for graph...."); //draw the axis lines for the graph bg.setColor(Color.black); bg.drawLine(graphPosX,graphPosY+graphHeight, graphPosX+graphWidth, graphPosY+graphHeight); bg.drawLine(graphPosX,graphPosY+graphHeight-1, graphPosX+graphWidth, graphPosY+graphHeight-1); bg.drawLine(graphPosX, graphPosY+graphHeight, graphPosX, graphPosY); bg.drawLine(graphPosX+1, graphPosY+graphHeight, graphPosX+1, graphPosY); //label the graph axes bg.setFont(new Font("Times", Font.BOLD, 9)); bg.drawString(""+0,graphPosX , graphPosY + graphHeight + 10) ; bg.drawString(""+(stepsPerRun*totalRuns),graphPosX + graphWidth -25, graphPosY + graphHeight + 10) ; bg.drawString(""+0,graphPosX -10 , graphYOrigin) ; bg.drawString(""+(-10),graphPosX -20 , graphPosY + graphHeight + yMargin ) ; bg.drawString(""+(10),graphPosX -20 , graphPosY + yMargin) ; //label the axes units bg.drawString("theta", graphPosX -40, graphPosY -10); bg.drawString("timestep", graphPosX + xMargin + (graphWidth/2) - 15, graphPosY + graphHeight + fieldWidth); //buffered_copy = createImage(bufSizeX,bufSizeY); //note will remain cleared until first time through animation loop cg = buffered_copy.getGraphics(); } }