/* animation based upon Elevator02.java (static tower+coriolis forces) ' ' Chris Davis 2005, 2006 ' JDK 1.1.6 ' ' Update record. ' -------------- ' v1 Created 27 Oct 2005 ' v2 Feeds and holds (imperfectly) 1 Nov 2005 ' v3 treats all masses the same, but masses below planet surface have ' zero gravitaional acceleration, and their velocity is increased ' by planetary rotation. Holdbody (lowest body in tower) is not ' subject to elastic forces. Working pulling up a few payloads, ' but holdbody not functioning 11 Dec 2005 ' v4 LIFTENGINE working 12 Dec 2005 ' v5 CLIMBER ENGINE working properly 16 Dec 2005 ' v6 rigid SIPHON code added (siphon not working) 17 Dec ' v7 HTML parameters 18 Dec ' v8 counterweight motion display ' maybe needs ties to be considered as a series of short lengths ' v10 constant acceleration start, new payloads given Vr radial ' velocity, distributed payload release, seems to remove most ' radial oscillation. 5 feb 06 ' v11 tie K varies with length. Introducing Young's modulus + Xsec ' area 6 feb 06 ' renamed ElevatorSiphon.java 8 feb 06 ' ' Elevator simulation ' -------------------- ' ' Elevator treated as 2D string-and-beads system (MKS units) ' ' (EARTH nth)11 --10 ---9 ---8 ---7 ---6 ---5 ---4 ---3 ---2 ---1 0 ' ' Static tower with Coriolis forces applied to bodies 19 - 23 to ' simulate rising bodies (although they actually keep still). ' ' The result is that the tower swings back and forth, with a variable ' period and amplitude. The cycle appears to be related to the ' lengthening and shortening of the tower, with swing period and ' amplitude increasing as tower shortens, decreasing as tower lengthens. ' ' Payloads below Earth surface have zero gravitational force exerted ' on them, and have tangential velocity r.We ' */ import java.awt.*; import java.util.*; import java.awt.event.*; import java.lang.Math; import java.awt.image.*; public class ElevatorSiphon extends java.applet.Applet implements Runnable { private Thread testThread = null; int count, xmax, ymax, hmargin; double hscale; Dimension appletSize; Image offImage; Graphics offGraphics; Color colorpalette[] = new Color[10]; int xpoints[] = new int[4]; int ypoints[] = new int[4]; int x1, x2, y1, y2, paletteindex; int p1, p2, p3, p4; Image img, img2; Graphics img2Graphics; int iw, ih; int pixels[]; int pixel2[]; boolean go = false; int sampletime = 1000; int B = 100; // total number of beads // tension, velocity, acceleration display variables int ndisplays; boolean showmaxt, showmaxv, showmaxa; boolean showmaxc, showmaxr; boolean showt, showv, showa, showc, showr; int hline[] = new int[20]; String label[] = { "N 0", "20000","T", "m/s 0", "2000", "V", "m/s' 0", "5", "A", "N 0", "300", "C", "N 0", "5000", "R" }; double ro[] = new double[B + 3]; // bead offset from radial int laboff[] = new int[20]; int ytower; int ytension; int yvelocity; int yaccel; int ycoriolis; int yradial; int x0, y0, w, b, xr; double ytscale, yascale, yvscale, yrscale, ycscale; double FC; double maxt[] = new double[B+3]; double maxv[] = new double[B+3]; double maxa[] = new double[B+3]; double maxc[] = new double[B+3]; double maxr[] = new double[B+3]; int d[] = new int[B+3]; // graphics bead radius int dy[] = new int[B+3]; // graphics bead tangential offset String s; int pe; // graphics pixel diameter of Earth // screen display variables boolean DisplayRotation = false; double dro[] = new double[B + 3]; // bead offset from radial double dr[] = new double[B + 3]; // bead radius int lastx = 0; int lasty = 0; Font f, fn; FontMetrics fm; double tsample = 10.0; // display sample time int EDATASIZE = 480; int edataptr = 0; boolean newedata = false; double edata[][] = new double[2][EDATASIZE]; boolean viewedata = false; int viewMode = 0; String elevatorName; double tot_radialdrop = 0; double tot_radialctr = 0; // tower variables boolean RunSiphon = false; // siphon or static tower boolean CoriolisPush = false; // Exert coriolis force. boolean RunLiftEngine = false; // lift engine running boolean RunClimberEngines = false; // lift engine running boolean DTvariable = false; // fixed/variable DT boolean BaseBoosted = false; // new masses accelerated up to speed double Re = 6378100.0; // Earth radius m double De = 2.0 * Re; // Earth diameter m double PI = 3.14159265; // Pi double Pe = 86164.09056; // Earth period (seconds) double m[] = new double[B + 3]; // bead mass double r[] = new double[B + 3]; // bead radial distance from planet double x[] = new double[B + 3]; // bead x position double y[] = new double[B + 3]; // bead y position double xx[] = new double[B + 3]; // bead x velocity double yy[] = new double[B + 3]; // bead y velocity double xxx[] = new double[B + 3]; // bead x accel double yyy[] = new double[B + 3]; // bead y acceleration double v[] = new double[B + 3]; // bead radial velocities double vta[] = new double[B + 3]; // bead tangential velocities double a[] = new double[B + 3]; // bead radial accelerations double l[] = new double[B + 3]; // bead tie free length (unstretched) double e[] = new double[B + 3]; // bead distance travelled in DT double emax; // highest bead distance moved double EMAX = 50.0; // maximum permissible distance moved double t[] = new double[B + 3]; // tensions of string(n) below bead(n) double avTension; // average tower tension double avAngle; // average tower angle from radial double c[] = new double[B + 3]; // coriolis forces double fr[] = new double[B + 3]; // radial counterthrust forces double k[] = new double[B + 3]; // string spring constants double p[][] = new double[B+3][6]; // 4 forces acting on all bodies int status[] = new int[B + 3]; // body status 0 = equator unlaunched // 1 = launched on tower // 2 = tower down // 3 = free orbit double DT = 10.0; // initial time step double old_dt = DT; double DTmin = 1000000.0; // minimum time step during run double DTmax = 0; // maximum time step during run double ltie = 10000000.0; // Unstretched string/tie length m double ymod = 1000.0E6; // Young's modulus (carbon nanotube) double atie = 0.0005; // tie cross-sectional area m2 // double atie = 0.000125; // tie cross-sectional area m2 double ktie = 0.5; // spring constant (arbitrary figure) double acceltie = 0.01; // initial tie constant acceleration double ltether; // entire tether free length double mb = 1000.0; // bead mass kg double counterweight = 1000.0; // end counterweight mass double RTOP = 239900000.0; // top bead initial radius m double RMAX = 250000000.0; // bead release radius (> RTOP) m double releasepart = 0.05; // fraction to release from tower double releasemass; // fractional release mass double releasepoint; // distance from RMAX to release boolean releaseFlag = false; // liftengine release flag int releaseNum = 0; // climber payload release number double VMAX = 500.0; // lowest bead max radial velocity m/s double vfeed = 0.0; // siphon lowest tie feed velocity double vlift = 0.0; // bead radial velocity m/s double lmax = 100.0; // max distance moved in DT double G = 6.672E-11; // gravitation constant G double Me = 5.9742E24; // Earth mass kg double We; // Earth angular velocity radians/s double rotationAngle; // Earth rotation angle int LIFTENGINE; // lift engine body number double TIME; // elapsed time s double timer; // timer int tcounter = 0; // timer counter double brakePowerOutput; // brake power output double startDelay = 5000.0; // delay before starting climbers/siphon double Synchronous; // Earth synchronous orbit radius int holdbody = 24; // body to hold at fixed position int HIGHEST, LOWEST, highest1; double fc, DL; int nbodies = B; int nth = B-1; boolean printStuff = false; int eventNum, eventTime, eventParam1, eventParam2; double debug[] = new double[100]; // debug data public void init() { int pm, pr, pp, nb, bm, br, bp, rnd, minc, ramin, ramax; int tl0, tlmax, tk, opt, rtr, rvmax, rlife, feed, vs, vt, towertype; double dt_requ, scaler; this.enableEvents( AWTEvent.MOUSE_EVENT_MASK ); appletSize = this.getSize(); setBackground(Color.white); count=1; xmax = appletSize.width; // graphics width ymax = appletSize.height; // graphics height hmargin = 5; // pixel margin width scaler = 1.0; offImage = createImage( xmax, ymax ); offGraphics = offImage.getGraphics(); f = new Font( "Dialog", Font.PLAIN, 10 ); fn = new Font( "Dialog", Font.PLAIN, 8 ); offGraphics.setFont( f ); fm = getFontMetrics( f ); towertype = 0; // get body configuration data try { dt_requ = (double)Integer.parseInt( getParameter("DELTA_T") ); DT = Math.abs( 1e-3 * dt_requ ); if ( dt_requ < 0 ) { DTvariable = true; EMAX = -dt_requ; } } catch( Exception e ) { } try { pm = Integer.parseInt( getParameter("PLANET_MASS") ); Me = pm * Math.pow( 10.0, 20); // planet mass } catch( Exception e ) { } try { pr = Integer.parseInt( getParameter("PLANET_RADIUS") ); Re = pr; // planet radius } catch( Exception e ) { } try { pp = Integer.parseInt( getParameter("PLANET_PERIOD") ); Pe = (double)pp; } catch( Exception e ) { } try { nb = Integer.parseInt( getParameter("NBODIES") ); if ( nb < B ) { nth = nb - 1; } } catch( Exception e ) { } try { bm = Integer.parseInt( getParameter("BODY_MASS") ); mb = bm; } catch( Exception e ) { } try { bm = Integer.parseInt( getParameter("COUNTERWEIGHT") ); counterweight = bm; } catch( Exception e ) { } try { tl0 = Integer.parseInt( getParameter("TIE_L0") ); ltie = tl0; } catch( Exception e ) { } try { tlmax = Integer.parseInt( getParameter("TIE_LMAX") ); lmax = tlmax; } catch( Exception e ) { } try { tk = Integer.parseInt( getParameter("TIE_K") ); ktie = 1e-3 * tk; } catch( Exception e ) { } try { tk = Integer.parseInt( getParameter("TIE_A") ); atie = 1e-6 * tk; // mm2 -> m2 } catch( Exception e ) { } try { tk = Integer.parseInt( getParameter("Y_MOD") ); ymod = 1e6 * tk; // giga Pascals } catch( Exception e ) { } try { tk = Integer.parseInt( getParameter("TIE_ACCEL") ); acceltie = 1e-3 * tk; // mm > m } catch( Exception e ) { } try { tk = Integer.parseInt( getParameter("RELEASE_FRACTION") ); releasepart = 1 / (double)tk; // 10 --> 1/10th } catch( Exception e ) { } try { rtr = Integer.parseInt( getParameter("TOWER_RADIUS") ); RTOP = rtr; } catch( Exception e ) { } try { rtr = Integer.parseInt( getParameter("MAX_TOWER_RADIUS") ); RMAX = rtr; } catch( Exception e ) { } try { rvmax = Integer.parseInt( getParameter("RADIAL_VMAX") ); VMAX = rvmax; } catch( Exception e ) { } try { startDelay = (double)Integer.parseInt( getParameter("START_DELAY") ); } catch( Exception e ) { } try { eventTime = Integer.parseInt( getParameter("EVENT_TIME") ); } catch( Exception e ) { } try { eventNum = Integer.parseInt( getParameter("EVENT_NUM") ); } catch( Exception e ) { } try { eventParam1 = Integer.parseInt( getParameter("EVENT_PARAM1") ); } catch( Exception e ) { } try { eventParam2 = Integer.parseInt( getParameter("EVENT_PARAM2") ); } catch( Exception e ) { } try { int view = Integer.parseInt( getParameter("VIEW") ); if ( view == 0 ) { DisplayRotation = false; } if ( view == 1 ) { DisplayRotation = true; scaler = 0.5; } if ( view == 3 ) { viewMode = 2; } if ( view == 4 ) { DisplayRotation = false; viewedata=true; } if ( view == 5 ) { viewMode = 1; } } catch( Exception e ) { } try { sampletime = Integer.parseInt( getParameter("SAMPLE_TIME") ); } catch( Exception e ) { } try { towertype = Integer.parseInt( getParameter("TOWER_TYPE") ); // tower type 0 is static tower if ( towertype == 0 ) { elevatorName = "Static tower"; } if ( towertype == 1 ) { CoriolisPush = true; elevatorName = "Coriolis push elevator"; } if ( towertype == 2 ) { RunLiftEngine = true; elevatorName = "Lift Engine elevator"; } if ( towertype == 3 ) { RunClimberEngines = true; elevatorName = "Climber elevator"; } if ( towertype == 4 ) { RunSiphon = true; elevatorName = "Siphon"; } } catch( Exception e ) { } hscale = (double)( xmax - (hmargin *2) ) / ( RMAX + 3 * Re ); // graphics scaling hscale = hscale * scaler; We = (PI * 2.0) / Pe; // Earth angular velocity double f = ((G * Me) / (We * We)); Synchronous = Math.pow( f, 0.333333 ); TIME = 0.0; timer = 0; TowerSetup(); if ( viewMode == 1 ) DisplayTensionScreenSetup(); } /* given (x,y) return index into pixels[i] */ int imageIndex( int x, int y, int iw ) { int i = y * iw + x; return ( i ); } public void start() { if (testThread == null) { testThread = new Thread(this, "Test1"); testThread.start(); } } public void processMouseEvent( MouseEvent e) { if ( e.getID() == MouseEvent.MOUSE_ENTERED ) { go = false; } else if ( e.getID() == MouseEvent.MOUSE_EXITED ) { go = true; } else if ( e.getID() == MouseEvent.MOUSE_RELEASED ) { offGraphics.setPaintMode(); offGraphics.setColor( Color.white ); offGraphics.fillRect( 0, 0, xmax, ymax ); x2 = e.getX(); y2 = e.getY(); p1 = 1 + x2 % 5; p2 = 1 + y2 % 5; p3 = 1 + Math.abs( x2-y2 ) % 5; p4 = 1 + (x2 + y2) % 6; go = true; } else super.processMouseEvent(e); } public void run() { double nextRepaintTime; Thread.currentThread().setPriority(Thread.MIN_PRIORITY); Thread myThread = Thread.currentThread(); repaint(); while (testThread == myThread) { if ( go ) { nextRepaintTime = TIME + tsample; while ( nextRepaintTime > TIME ) { ElevatorEngine(DT); } repaint(); count++; } try { Thread.sleep(20); } catch (InterruptedException e){ } } } public void TowerSetup() { int n; double l1, v1; ktie = ymod * atie / ltie; System.out.println( "ktie = " + ktie ); // create chain of beads for ( n = 0; n < nbodies; n++ ) { m[n] = mb; } m[1] = counterweight; // set up equilibrium tower with top bead at radius RTOP. k[0] = 0; // no string above first bead t[0] = 0; // no tension in string above 1st bead x[0] = Re-100.0; y[0] = 0.0; r[0] = Re-100.0; l[0] = ltie; status[0] = 1; x[B + 1] = Re; // unused final bead HIGHEST = 1; // current tower top bead LOWEST = nth-1; x[1] = RTOP; // start at top and work downward r[1] = RTOP; for ( n = 1; n <= B; n++ ) { xx[n] = 0.0; a[n] = 0.0; l[n] = ltie; k[n] = ymod * atie / ltie; y[n] = 0.0; if ( x[n] > Re ) { if ( !RunSiphon ) { if ( x[n] > Synchronous ) { LIFTENGINE = n; } } status[n] = 1; p[n][0] = -(G * Me * m[n]) / (x[n] * x[n]); // gravitational force p[n][1] = m[n] * x[n] * We * We; // centrifugal force p[n][2] = t[n - 1]; // upper tie tension t[n] = (p[n][0] + p[n][1] + p[n][2]); // required lower tension for equilibrium DL = t[n] / k[n]; // required tie increase in length x[n+1] = x[n] - (l[n] + DL); // ..gives position of next body if ( x[n+1] < Re ) { l1 = x[n] - Re; v1 = 1 + t[n] / (atie * ymod); l[n] = l1 / v1; // free tie length required l[n+1] = l[n+1] + (ltie-l[n]); // next tie down lengthened } r[n+1] = x[n+1]; yy[n] = x[n] * We; // tangential velocity = r.W LOWEST = n; } else { l[n] = ltie; x[n] = Re - 100.0; // below planet surface status[n] = 0; r[n] = x[n]; t[n] = 0.0; x[n + 1] = Re - 100.0; } } highest1 = HIGHEST; k[B] = 0; // no strings below last bead k[B+1] = 0; x[B+1] = Re-100.0; status[B+1] = 0; x[B+2] = Re-100.0; status[B+2] = 0; a[B+1] = 0; a[B+2] = 0; m[nth] = Me; // nth body is Earth x[nth] = 0; // Earth centre at origin y[nth] = 0; status[nth] = 0; k[nth-1] = 0.0; // no tie to centre of Earth holdbody = LOWEST+1; fc = 2.0 * We * VMAX; // coriolis force 2mwV on 1 kg // ..or coriolis acceleration releasemass = releasepart * m[1]; // siphon release mass releasepoint = (1.0 - 1.5 * releasepart) * l[0]; // siphon start release point } // calculate body motions over interval dt public void ElevatorEngine( double dt ) { double lx, ly, acc, d, dl, f, rsin, rcos; double vr, vt, csa, sna, amax, endv; int n, o, dbn, lowest; boolean tower_break; rsin = Math.sin( rotationAngle ); // sine of planet rotation angle rcos = Math.cos( rotationAngle ); // cos of planet rotation angle // Zero body accelerations, calculate radial distance for ( n = 0; n < nth; n++ ) { xxx[n] = 0.0; yyy[n] = 0.0; r[n] = Math.sqrt( x[n] * x[n] + y[n] * y[n] ); if ( k[n] > 0 ) { if ( l[n] > 1.0 ) { k[n] = ymod * atie / l[n]; } else { k[n] = ymod * atie; } } } // calculate new body gravitational acceleration for ( n = 0; n < nth; n++ ){ // if above planet surface, calculate acceleration if ( r[n] > Re ) { lx = x[n] - x[nth]; // x distance from m ly = y[n] - y[nth]; // y distance .. .. d = Math.sqrt(lx * lx + ly * ly); // distance .. .. acc = -(G * m[nth]) / (d * d); // acceleration towards planet xxx[n] = xxx[n] + acc * lx / d; // x component of accel yyy[n] = yyy[n] + acc * ly / d; // y component of accel } else { // gravitational acceleration = 0 // payload fallen to earth? if ( (n <= LOWEST) && (n > 0) ) { if ( Math.abs( v[n] ) > 300.0 ) { // System.out.println( n + " " + (int)(TIME) + " ^ " + (float)(v[n]) + " > " + (float)(vta[n]) ); } } } } // calculate new body elastic acceleration for ( n = 1; n < nth; n++ ){ o = n + 1; // next mass down lx = x[n] - x[o]; // x distance from m ly = y[n] - y[o]; // y distance .. .. d = Math.sqrt(lx * lx + ly * ly); // tie length if ( d == 0 ) d = 1.0; dl = l[n] - d; // dl = length change f = k[n] * dl; // force = K.dl if ( f > 0 ) { f = 0; } // tension only (for now) t[n] = -f; // elastic acceleration = force / mass // holdbody is not subject to elastic forces. if ( n != holdbody ) { xxx[n] = xxx[n] + (f * lx)/(d * m[n]); // x component of accel yyy[n] = yyy[n] + (f * ly)/(d * m[n]); // y component of accel } if ( o != holdbody ) { xxx[o] = xxx[o] - (f * lx)/(d * m[o]); // x component of accel yyy[o] = yyy[o] - (f * ly)/(d * m[o]); // y component of accel } } // add acceleration due to Coriolis force to lower payloads // ( used to simulate coriolis forces from rising payloads // on a static tower ). if ( CoriolisPush ) { Coriolis(); } // calculate new body speeds for ( n = 0; n < nth; n++ ){ xx[n] = xx[n] + xxx[n] * dt; // new x velocity yy[n] = yy[n] + yyy[n] * dt; // new y velocity // masses at or below planet surface have tangential velocity // due to planet rotation, and no negative radial velocity. if ( r[n] <= Re ) { lx = x[n] - x[nth]; // x distance from m ly = y[n] - y[nth]; // y distance .. .. d = Math.sqrt(lx * lx + ly * ly); // distance .. .. sna = ly / d; csa = lx / d; // x-y velocities --> r-t velocities vr = xx[n] * csa + yy[n] * sna; if ( vr < 0.0 ) { vr = 0.0; } // no -ve radial velocity vt = -d * We; // tangential velocity // r-t velocities --> x-y velocities xx[n] = vr * csa + vt * sna; yy[n] = vr * sna - vt * csa; } } // if siphon, fix tangential velocities to planetary angular velocity if ( RunSiphon ) { fix_tangential_velocity(); } // calculate new body locations after time dt. // It might be expected that this would be found using // s = ut + 0.5at^2, but there is no need to perform this // integration, as the simulation model is itself performing // the integration over small time steps. emax = 0.0; for ( n = 0; n < nth; n++ ){ lx = xx[n] * dt; ly = yy[n] * dt; e[n] = Math.sqrt( lx * lx + ly * ly ); if ( e[n] > emax ) { emax = e[n]; } x[n] = x[n] + lx; // new x y[n] = y[n] + ly; // new y } // calculate new radial distances and velocities from base planet for ( n = 0; n < nth; n++ ) { r[n] = Math.sqrt( x[n] * x[n] + y[n] * y[n] ); v[n] = xx[n] * (x[n] - x[nth]) / r[n] + yy[n] * (y[n] - y[nth]) / r[n]; vta[n] = xx[n] * (y[n] - y[nth]) / r[n] + yy[n] * (x[n] - x[nth]) / r[n]; a[n] = xxx[n] *(x[n] - x[nth]) / r[n] + yyy[n] * (y[n] - y[nth]) / r[n]; } // Lift engine hauls up tether below it, pulling up payloads, // releasing them when they reach the liftengine payload. if ( RunLiftEngine ) { LiftEngine(); } // Climber engine raises climbers up tether, // releasing them when they reach the liftengine payload. if ( RunClimberEngines ) { ClimberEngine(); } // Siphon engine reels out lowest tie, adding payloads. if ( RunSiphon ) { SiphonEngine(); } brakePowerOutput = t[LOWEST] * vfeed; double angle = Math.atan2( y[1], x[1] ) - rotationAngle; rotationAngle = rotationAngle + We * DT; if ( rotationAngle > (2.0 * PI) ) { rotationAngle = rotationAngle - ( 2.0 * PI ); } TIME = TIME + DT; eventCheck(); if ( printStuff ) { if ( (int)x[1] != 0 ) { debug[0] = x[0]; debug[1] = y[0]; debug[2] = x[1]; debug[3] = y[1]; debug[4] = xx[1]; debug[5] = yy[1]; debug[6] = xxx[1]; debug[7] = yyy[1]; debug[8] = TIME; debug[9] = r[1]; debug[10] = v[1]; debug[11] = releaseNum; debug[12] = LOWEST; debug[13] = holdbody; debug[14] = m[holdbody]; debug[15] = x[holdbody]; debug[16] = y[holdbody]; } else { go = false; } System.out.println( "Time " + (int)debug[8] ); System.out.println( "x0 " + (int)debug[0] + " y0 " + (int)debug[1] ); System.out.println( "x1 " + (int)debug[2] + " y1 " + (int)debug[3] ); System.out.println( "xx1 " + (int)debug[4] + " yy1 " + (int)debug[5] ); System.out.println( "xxx1 " + (int)debug[6] + " yyy1 " + (int)debug[7] ); System.out.println( "r1 " + (int)debug[9] + " v1 " + (int)debug[10] ); System.out.println( "Releases " + (int)debug[11] ); System.out.println( "lowest " + (int)debug[12] + " holdbody " + (int)debug[13] ); System.out.println( "mh " + (int)debug[14] + " xh " + (int)debug[15] + " yh " + (int)debug[16] ); } if ( TIME > timer ) { timer = timer + (double)sampletime; tcounter++; Measure(); System.out.println( ymod / 1000000.0 +" Gpa" ); System.out.println( "Time: " + (int)(TIME) + " " + a[20] + " " + xxx[20] + " " + yyy[20] ); } if ( DTvariable ) { DT = DT * EMAX / emax; } } public void findCoriolisForces() { int n; double csa, sna, at; csa = Math.cos(rotationAngle); sna = Math.sin(rotationAngle); for ( n = 1; n <= LOWEST; n++ ) { // x-y accelerations --> r-t accelerations at = xxx[n] * sna - yyy[n] * csa; // c[n] = m[n] * at; } } // exert coriolis force on bodies below liftengine public void Coriolis() { int n; double lx, ly; for ( n = LIFTENGINE+1; n <= LOWEST; n++ ) { if ( r[n] > Re ) { lx = x[n] - x[nth]; // x distance from planet centre ly = y[n] - y[nth]; // y distance .. .. xxx[n] = xxx[n] + ( fc * ly / r[n] ); yyy[n] = yyy[n] - ( fc * lx / r[n] ); } } } // Lift engine hauls up chain of payloads below, // releasing them when they reach the lift engine. public void LiftEngine() { int n; if ( TIME > startDelay ) { l[LIFTENGINE] = l[LIFTENGINE] - (vlift * DT); l[LOWEST] = l[LOWEST] + (vlift * DT); if ( l[LOWEST] > ltie ) { LOWEST++; holdbody++; l[LOWEST] = 1.0; l[LOWEST-1] = l[LOWEST-1] + 1.0; } // release payload into free orbit if ( releaseFlag ) { // unused payload 0 becomes released payload x[0] = x[LIFTENGINE+1]; y[0] = y[LIFTENGINE+1]; xx[0] = xx[LIFTENGINE+1]; yy[0] = yy[LIFTENGINE+1]; m[0] = m[LIFTENGINE+1]; r[0] = r[LIFTENGINE+1]; v[0] = xx[0] * (x[0] - x[nth]) / r[0] + yy[0] * (y[0] - y[nth]) / r[0]; releaseNum++; l[LIFTENGINE] = l[LIFTENGINE] + l[LIFTENGINE+1]; // take position, atrributes of next body down for ( n = LIFTENGINE+1; n <= LOWEST+1; n++ ) { m[n] = m[n+1]; l[n] = l[n+1]; k[n] = k[n+1]; x[n] = x[n+1]; y[n] = y[n+1]; xx[n] = xx[n+1]; yy[n] = yy[n+1]; r[n] = r[n+1]; } LOWEST--; holdbody--; DT = old_dt; releaseFlag = false; } // change DT to complete reeling in body if ( l[LIFTENGINE] < (1.2 * vlift * DT) ) { old_dt = DT; DT = l[LIFTENGINE] / vlift; releaseFlag = true; } // calculate total tether length (should be constant) ltether = 0.0; for ( n = 1; n <= LOWEST; n++ ) { ltether = ltether + l[n]; } // accelerate up to top radial velocity if ( vlift < VMAX ) vlift = vlift + VMAX / 1000.0; } } // Climber engine raises climbers below LIFTENGINE, // releasing them when they nearly reach the lift engine. // // A climber moving at a constant speed along a stretched tie // moves only a fraction of unstretched free length. public void ClimberEngine() { int n; double dl, fraction, reel; if ( TIME > startDelay ) { // move climbers up tether for ( n = LIFTENGINE+1; n <= LOWEST; n++ ) { if ( k[n-1] > 0 ) { dl = t[n-1] / k[n-1]; // tie extension fraction = l[n+1] / ( l[n+1] + dl); // fraction of free length reel = fraction * vlift * DT; if ( reel < l[n-1] ) { l[n-1] = l[n-1] - reel; // shorten upper tie l[n] = l[n] + reel; // lengthen lower tie } } } // start new climber at base if ( l[LOWEST] > ltie ) { LOWEST++; holdbody++; l[LOWEST] = 1.0; } // if liftengine tie length is short, release payload if ( l[LIFTENGINE] < (1.2 * vlift * DT) ) { // unused payload 0 becomes released payload x[0] = x[LIFTENGINE+1]; y[0] = y[LIFTENGINE+1]; xx[0] = xx[LIFTENGINE+1]; yy[0] = yy[LIFTENGINE+1]; m[0] = m[LIFTENGINE+1]; r[0] = r[LIFTENGINE+1]; releaseNum++; l[LIFTENGINE] = l[LIFTENGINE] + l[LIFTENGINE+1]; // take position, attributes of next body down for ( n = LIFTENGINE+1; n <= LOWEST+1; n++ ) { m[n] = m[n+1]; l[n] = l[n+1]; k[n] = k[n+1]; x[n] = x[n+1]; y[n] = y[n+1]; xx[n] = xx[n+1]; yy[n] = yy[n+1]; r[n] = r[n+1]; } LOWEST--; holdbody--; } // calculate total tether length (should be constant) ltether = 0.0; for ( n = 1; n <= LOWEST; n++ ) { ltether = ltether + l[n]; } // accelerate up to top radial velocity if ( vlift < VMAX ) vlift = vlift + VMAX / 1000.0; } } // SIPHON. // fix tangential velocity to radius x angular velocity // in a rigid tower. public void fix_tangential_velocity() { int n; double vr, vt, dvt; double csa, sna; csa = Math.cos(rotationAngle); sna = Math.sin(rotationAngle); for ( n = 1; n < nth; n++ ) { // x-y velocities --> r-t velocities vr = xx[n] * csa + yy[n] * sna; vt = xx[n] * sna - yy[n] * csa; // new tangential velocity dvt = vt + r[n] * We; //change of tangential velocity vt = -r[n] * We; // dvt is change of velocity in period DT, so acceleration per // unit time is dvt/DT, and force = m.dvt/DT. c[n] = m[n] * dvt / DT; // r-t velocities --> x-y velocities xx[n] = vr * csa + vt * sna; yy[n] = vr * sna - vt * csa; } } public void SiphonEngine() { int n; double vr, vt, dvt; double csa, sna, rfs; // constant acceleration up to VMAX if ( vfeed < VMAX ) { vfeed = vfeed + acceltie * DT; } else { vfeed = VMAX; } // feed out stretched tie // rfs is ratio of free to stretched length rfs = l[LOWEST] / ( l[LOWEST] + t[LOWEST] / k[LOWEST] ); l[LOWEST] = l[LOWEST] + rfs * vfeed * DT; // add new payload if ( l[LOWEST] > ltie ) { LOWEST++; holdbody++; l[LOWEST] = 1.0; l[LOWEST-1] = l[LOWEST-1] - 1.0; v[LOWEST] = vfeed; // give new payload x-y velocity n = LOWEST; csa = Math.cos(rotationAngle); sna = Math.sin(rotationAngle); // new tangential velocity vr = v[n]; vt = -r[n] * We; // r-t velocities --> x-y velocities xx[n] = vr * csa + vt * sna; yy[n] = vr * sna - vt * csa; } // release payload incrementally, not all at once. if ( (RMAX - r[1]) < releasepoint ) { m[0] = m[0] + releasemass; m[1] = m[1] - releasemass; releasepoint = releasepoint - releasepart * ltie; // next release point } // if top payload past RMAX, release last of payload if ( r[1] > RMAX ) { // take position, attributes of next body down for ( n = 0; n <= LOWEST+1; n++ ) { m[n] = m[n+1]; l[n] = l[n+1]; k[n] = k[n+1]; x[n] = x[n+1]; y[n] = y[n+1]; xx[n] = xx[n+1]; yy[n] = yy[n+1]; r[n] = r[n+1]; } k[0] = 0; // mass 0 is in free motion releasemass = releasepart * m[1]; releasepoint = (1.0 - releasepart - 0.5 * releasepart) * l[0]; releaseNum++; LOWEST--; holdbody--; } } // measure a few things public void Measure( ) { int n; double lastAngle = 0; lastAngle = avAngle; avAngle = 0.0; avTension = 0.0; for ( n = 1; n <= LOWEST; n++ ) { avTension = avTension + t[n]; avAngle = avAngle + Math.atan2( y[n], x[n] ); } avTension = avTension / (double)LOWEST; avAngle = avAngle / (double)LOWEST; avAngle = avAngle - rotationAngle; if ( avAngle > ( 2.0 * PI ) ) { avAngle = avAngle - ( 2.0 * PI ); } if ( avAngle < -( 2.0 * PI ) ) { avAngle = avAngle + ( 2.0 * PI ); } // crude bug fix if ( Math.abs( lastAngle - avAngle ) > 0.2 ) { avAngle = lastAngle; } // store measurements in circular buffer edata[0][edataptr] = avTension; edata[1][edataptr] = avAngle; newedata = true; edataptr++; if ( edataptr >= EDATASIZE ) edataptr = 0; } public void eventCheck( ) { int n; if ( (TIME >= eventTime) && (eventTime > 0) ) { if ( eventNum == 1 ) { for ( n = 0; n < nth; n++ ) { k[n] = 0.0; // shatter tower } } else { if ( eventNum == 2 ) { k[LOWEST] = 0.0; // release tower } else { if ( eventNum == 3 ) { k[eventParam1] = 0.0; // break tower at point } else { if ( eventNum == 4 ) { RunLiftEngine = false; // stop climbers RunClimberEngines = false; RunSiphon = false; CoriolisPush = false; } else { if ( eventNum == 5 ) { go = false; // stop the simulation printStuff = true; // enable debug print } } } } } eventTime = 0; } } public void paint(Graphics g) { update(g); } public void update(Graphics g) { int xorigin, yorigin; int n, k0, k1, yoff; double val, angle; if ( viewMode == 0 ) { if ( viewedata ) { if ( newedata ) drawGraph( g ); } // for rotating view, set origin at centre, halve hscale, // and set dro[n] = y[n], dr[n] = x[n] if ( DisplayRotation ) { xorigin = 240; // rotating display yorigin = 200; for ( n = 0; n < nth; n++ ) { dro[n] = y[n]; dr[n] = x[n]; } angle = rotationAngle; } else { xorigin = 20; // static equatorial display yorigin = 200; for ( n = 0; n < nth; n++ ) { // find radial angle of body to radial rotationangle angle = Math.atan2( y[n], x[n] ) - rotationAngle; dr[n] = r[n] * Math.cos( angle ); dro[n] = r[n] * Math.sin( angle ); } angle = 0; } // draw something into offGraphics offGraphics.setPaintMode(); offGraphics.setColor( Color.white ); if ( viewedata ) { yoff = 180; } else { yoff = 0; } if (TIME > 0 ) { offGraphics.fillRect( 0, 0, xmax, ymax - yoff ); } // draw equatorial plane x0 = xorigin + (int)((double)xmax * Math.cos(angle) ); y0 = yorigin + (int)((double)xmax * Math.sin(angle) ); offGraphics.setColor( Color.lightGray ); // equatorial plane offGraphics.drawLine( xorigin, yorigin, x0 , y0 ); // draw earth x0 = xorigin - (int)( Re * hscale); y0 = yorigin - (int)( Re * hscale ); w = (int)( 2.0 * Re * hscale ); offGraphics.setColor( Color.blue ); offGraphics.fillOval( x0, y0, w, w ); // draw synchronous point x0 = xorigin + (int)( Synchronous * hscale ); offGraphics.setColor( Color.lightGray ); // synchronous radius offGraphics.drawLine( x0, yorigin-5, x0, yorigin+5 ); // draw masses for ( n = 0; n < nth; n++ ) { x0 = xorigin + (int)(dr[n] * hscale); y0 = yorigin + (int)(dro[n] * hscale); x1 = xorigin + (int)(dr[n+1] * hscale); y1 = yorigin + (int)(dro[n+1] * hscale); if ( t[n] > 0 ) { offGraphics.setColor( Color.blue ); } else { offGraphics.setColor( Color.red ); } if ( k[n] > 0 ) { offGraphics.drawLine( x0, y0, x1, y1 ); } // released payload if ( n == 0 ) { offGraphics.setColor( Color.green ); k0 = fm.stringWidth( "" + releaseNum ) - 1; offGraphics.drawString( "" + releaseNum, x0, y0-2 ); } // top of tower if ( n == 1 ) { offGraphics.setColor( Color.blue ); k1 = (int)( r[n] / 1000.0 ); k0 = fm.stringWidth( "" + k1 ) - 1; offGraphics.drawString( "" + k1, x0, y0-2 ); } offGraphics.setColor( Color.black ); if ( n == LIFTENGINE ) offGraphics.setColor( Color.red ); if ( n == 0 ) offGraphics.setColor( Color.green ); offGraphics.fillOval( x0-1, y0-1, 3, 3 ); } s = elevatorName; s = s + " Bead mass " + (int)mb + " kg"; s = s + " Tie length " + (int)(ltie/1000.0) + " km"; s = s + " Spring constant " + ktie; offGraphics.drawString( s, 2, 12 ); s = "" + "Counterweight " + (int)m[1] + " kg "; s = s + " Max radial velocity " + VMAX + " m/s"; s = s + " Lowest tie tension " + (int)t[LOWEST] + " N "; offGraphics.drawString( s , 2, 24 ); s = "" + (int)TIME + " s"; val = (float)(ltether/1000.0); s = s + " tether " + val + "km "; val = ((float)((int)(DT * 100000.0))) / 100000.0; s = s + " DT " + val; offGraphics.drawString( s , 2, 36 ); } else if ( viewMode==1 ) { showTensionGraphics( g ); } else { drawCounterweightMotion( g ); } // draw offGraphics into Graphics g.drawImage( offImage, 0, 0, this ); } // counterweight motion trail display public void drawCounterweightMotion( Graphics g ) { int xorigin, yorigin; int n, k0, k1, yoff, rcircle; double val, angle, dscale; // static equatorial display n = 1; // find radial angle of body to radial rotationangle angle = Math.atan2( y[n], x[n] ) - rotationAngle; dr[n] = r[n] * Math.cos( angle ); dro[n] = r[n] * Math.sin( angle ); dscale = hscale * 4.0; xorigin = (xmax/2) - (int)( dscale * RTOP ); yorigin = ymax/2; if ( TIME < 10.0 ) { offGraphics.setColor( Color.lightGray ); rcircle = (int)(RTOP * dscale); x0 = xorigin - rcircle; y0 = yorigin - rcircle; x1 = 2 * rcircle; y1 = 2 * rcircle; offGraphics.drawOval( x0, y0, x1, y1 ); x0 = 0; y0 = ymax/2; x1 = xmax; y1 = ymax/2; offGraphics.drawLine( x0, y0, x1, y1 ); rcircle = (int)(Synchronous * dscale); x0 = xorigin - rcircle; y0 = yorigin - rcircle; x1 = 2 * rcircle; y1 = 2 * rcircle; offGraphics.setColor( Color.cyan ); offGraphics.drawOval( x0, y0, x1, y1 ); offGraphics.setColor( Color.black ); s = elevatorName + " " + (int)(RTOP/1000.0) + " km"; offGraphics.drawString( s, 2, 12 ); s = "Bead mass " + (int)mb + " kg"; offGraphics.drawString( s, 2, 24 ); s = "Tie length " + (int)(ltie/1000.0) + " km"; offGraphics.drawString( s, 2, 36 ); s = "Spring constant " + ktie; offGraphics.drawString( s, 2, 48 ); s = "Counterweight " + (int)(m[1]/1000.0) + " tonnes "; offGraphics.drawString( s, 2, 60 ); s = "Max radial velocity " + VMAX + " m/s"; offGraphics.drawString( s, 2, 72 ); if (DTvariable) { s = "DT var: EMAX = " + EMAX + " m"; } else { s = "DT " + DT + " s "; } offGraphics.drawString( s , 2, 84 ); // draw graph 0 offGraphics.setColor( Color.lightGray ); offGraphics.drawLine( 0, ymax-10, xmax, ymax-10 ); } // clear and repaint time offGraphics.setColor( Color.white ); offGraphics.fillRect( 0, 87, 100, 108 ); offGraphics.setColor( Color.black ); s = "Time " + (int)( TIME ); offGraphics.drawString( s, 2, 96 ); x0 = xorigin + (int)(dr[n] * dscale); y0 = yorigin + (int)(dro[n] * dscale); offGraphics.setColor( Color.black ); if ( lastx != x0 ) { offGraphics.fillOval( lastx, lasty, 1, 1 ); } if ( lasty != y0 ) { offGraphics.fillOval( lastx, lasty, 1, 1 ); } offGraphics.setColor( Color.red ); offGraphics.fillOval( x0, y0, 1, 1 ); lastx = x0; lasty = y0; // draw graph x0 = tcounter; y0 = ymax - 10 + (int)(dro[n] * dscale); offGraphics.setColor( Color.black ); // offGraphics.fillOval( x0, y0, 1, 1 ); } // rolling graph of elevator angle and average tension over time public void drawGraph( Graphics g ) { int n, ptr; double gscale[] = new double[2]; int ya0, ya1, yb0, yb1; offGraphics.setColor( Color.white ); offGraphics.fillRect( 0, ymax-180, xmax, ymax ); gscale[0] = 0.01; gscale[1] = -400.0; // draw zero line offGraphics.setColor( Color.lightGray ); offGraphics.drawLine( 0, ymax-20, xmax, ymax-20 ); ptr = edataptr; for ( n = 1; n <= EDATASIZE; n++ ) { ya0 = (int)( gscale[0] * edata[0][ptr] ); ya1 = (int)( gscale[1] * edata[1][ptr] ); ptr++; if ( ptr >= EDATASIZE ) ptr = 0; yb0 = (int)( gscale[0] * edata[0][ptr] ); yb1 = (int)( gscale[1] * edata[1][ptr] ); offGraphics.setColor( Color.red ); offGraphics.drawLine( n, ymax-20-ya0, n+1, ymax-20-yb0 ); offGraphics.setColor( Color.blue ); offGraphics.drawLine( n, ymax-20-ya1, n+1, ymax-20-yb1 ); } newedata = false; } // tension, radial velocity, acceleration display (from Elevator01) public void DisplayTensionScreenSetup() { int k0, k1; double z; f = new Font( "Dialog", Font.PLAIN, 10 ); fn = new Font( "Dialog", Font.PLAIN, 8 ); showt = true; showv = true; showa = true; showc = true; showr = false; ytower = 60; ytension = 130; yvelocity = 175; yaccel = 225; ycoriolis = 275; yradial = 325; ytscale = 0.002; yvscale = 0.01; yascale = 3.0; ycscale = 0.05; yrscale = 0.005; hline[0] = ytension; hline[3] = yvelocity; hline[6] = yaccel; hline[9] = ycoriolis; hline[12] = yradial; // draw graph scales offGraphics.setFont( fn ); fm = getFontMetrics( fn ); ndisplays = 0; if ( showt ) { laboff[0] = fm.stringWidth( label[0] ) + 2; z = 20000.0; // tension s = "" + (int)z; laboff[1] = fm.stringWidth( s ) + 2; y1 = ytension; hline[1] = ytension - (int)(z * ytscale); laboff[2] = 25; hline[2] = 0; ndisplays++; } if ( showv ) { laboff[3] = fm.stringWidth( label[3] ) + 2; z = 2000.0; // velocity s = "" + (int)z; laboff[4] = fm.stringWidth( s ) + 2; hline[4] = yvelocity - (int)(z * yvscale); laboff[5] = 25; hline[5] = 0; ndisplays++; } if ( showa ) { laboff[6] = fm.stringWidth( label[6] ) + 2; z = 5.0; // acceleration s = "" + (int)z; laboff[7] = fm.stringWidth( s ) + 2; hline[7] = yaccel - (int)(z * yascale); laboff[8] = 25; hline[8] = 0; ndisplays++; } if ( showc ) { laboff[9] = fm.stringWidth( label[9] ) + 2; z = 300.0; // coriolis counterthrust s = "" + (int)z; laboff[10] = fm.stringWidth( s ) + 2; hline[10] = ycoriolis - (int)(z * ycscale); laboff[11] = 25; hline[11] = 0; ndisplays++; } if ( showr ) { laboff[12] = fm.stringWidth( label[12] ) + 2; z = 5000.0; // radial counterthrust s = "" + (int)z; laboff[13] = fm.stringWidth( s ) + 2; hline[13] = yradial - (int)(z * yrscale); laboff[14] = 25; hline[14] = 0; ndisplays++; } showmaxt = false; showmaxv = false; showmaxa = false; showmaxc = false; showmaxr = false; for (int n = 0; n <= (B+1); n++ ) { maxt[n] = 0; maxv[n] = 0; maxa[n] = 0; maxc[n] = 0; maxr[n] = 0; } } // The graphic display is hooked to RMAX, the radius at which bodies // are released from the rising tower, in order to keep the public void showTensionGraphics(Graphics g) { int n, k0, k1, planetx; double val; String s; for ( n = 1; n < LOWEST+1; n++ ) { ro[n] = y[n] - r[n] * Math.sin( rotationAngle ); } /* draw something into offGraphics*/ offGraphics.setPaintMode(); offGraphics.setColor( Color.white ); offGraphics.fillRect( 0, 0, xmax, ymax ); // draw labels offGraphics.setFont( fn ); for ( n = 0; n <= ((ndisplays-1) * 3); n = n + 3 ) { offGraphics.setColor( Color.lightGray ); d[HIGHEST] = (int)((Re + r[HIGHEST]) * hscale) + hmargin; d[LOWEST+1] = (int)((Re + r[LOWEST+1]) * hscale) + hmargin; offGraphics.drawLine( d[LOWEST+1] - 1, hline[n], d[HIGHEST], hline[n]); offGraphics.drawLine( d[LOWEST+1] - 1, hline[n+1], d[HIGHEST], hline[n+1]); offGraphics.setColor( Color.black ); offGraphics.drawString( label[n], d[LOWEST+1] - laboff[n], hline[n] ); offGraphics.drawString( label[n+1], d[LOWEST+1] - laboff[n+1], hline[n+1] + 3 ); offGraphics.drawString( label[n+2] , d[LOWEST+1] - laboff[n+2], hline[n] - 8 ); } // draw strings and beads b = 0; planetx = (int)((Re + r[LOWEST+1]) * hscale) + hmargin; offGraphics.setColor( Color.lightGray ); offGraphics.drawLine( planetx, ytower, xmax-hmargin, ytower ); offGraphics.setFont( f ); fm = getFontMetrics( f ); for ( n = HIGHEST; n <= ( LOWEST + 1 ); n++ ) { d[b] = (int)((Re + r[n]) * hscale) + hmargin; d[b+1] = (int)((Re + r[n+1]) * hscale) + hmargin; dy[b] = (int)(ro[n] * hscale) + ytower; dy[b+1] = (int)(ro[n+1] * hscale) + ytower; offGraphics.setColor( Color.lightGray ); offGraphics.drawLine( d[b], ytower, d[b], ymax ); if ( t[n] > 0 ) { offGraphics.setColor( Color.blue ); } else { offGraphics.setColor( Color.red ); } if ( k[n] > 0 ) { offGraphics.drawLine( d[b], dy[b], d[b+1], dy[b+1] ); } // draw bead/body offGraphics.setColor( Color.black ); offGraphics.fillOval( d[b]-1, dy[b]-1, 3, 3 ); // draw Earth if ( n == (LOWEST+1) ) { x0 = planetx - (int)( 2.0 * Re * hscale); y0 = ytower - (int)( Re * hscale ); w = (int)( 2.0 * Re * hscale ); offGraphics.setColor( Color.blue ); offGraphics.fillOval( x0, y0, w, w ); offGraphics.setColor( Color.white ); // mark synchronous point x1 = d[b+1] + (int)( (Synchronous - Re) * hscale ); offGraphics.setColor( Color.black ); offGraphics.drawLine( x1, ytower - 5, x1, ytower + 8 ); offGraphics.drawLine( x1-5, ytower+3, x1, ytower + 8 ); offGraphics.drawLine( x1+5, ytower+3, x1, ytower + 8 ); offGraphics.drawString( "s", x1 - 2, ytower - 7 ); // mark release radius x1 = d[b+1] + (int)( (RMAX - Re) * hscale ); offGraphics.setColor( Color.black ); offGraphics.drawLine( x1, ytower - 5, x1, ytower + 5 ); offGraphics.drawString( "r", x1 - 2, ytower - 7 ); } if ( n == HIGHEST ) { offGraphics.setColor( Color.black ); k1 = n + releaseNum; k0 = fm.stringWidth( "" + k1 ) - 1; offGraphics.drawString( "" + k1, d[b] - k0, ytower - 2 ); k1 = (int)( r[n] / 1000.0 ); k0 = fm.stringWidth( "" + k1 ) - 1; offGraphics.drawString( "" + k1, d[b] - k0, ytower-12 ); } if ( n == LOWEST ) { offGraphics.setColor( Color.black ); k1 = n + releaseNum; offGraphics.drawString( "" + k1, d[b], ytower - 2 ); } // draw string tensions if (showt) { xpoints[0] = d[b]; xpoints[1] = d[b]; xpoints[2] = d[b+1]; xpoints[3] = d[b+1]; ypoints[0] = ytension; ypoints[1] = ytension - (int)( t[n] * ytscale); ypoints[2] = ytension - (int)( t[n] * ytscale); ypoints[3] = ytension; offGraphics.setColor( Color.blue ); offGraphics.fillPolygon( xpoints, ypoints, 4); if ( showmaxt ) { y1 = ytension - (int)( maxt[n] * ytscale); offGraphics.drawLine( d[b], y1, d[b+1], y1 ); } offGraphics.setColor( Color.black ); } // draw bead velocities if (( n < B ) && ( showv )) { xpoints[0] = d[b]; xpoints[1] = d[b]; xpoints[2] = d[b+1]; xpoints[3] = d[b+1]; ypoints[0] = yvelocity; ypoints[1] = yvelocity - (int)( v[n] * yvscale ); ypoints[2] = yvelocity - (int)( v[n+1] * yvscale ); ypoints[3] = yvelocity; offGraphics.setColor( Color.red ); offGraphics.fillPolygon( xpoints, ypoints, 4); if ( showmaxv ) { y1 = yvelocity - (int)( maxv[n] * yvscale); y2 = yvelocity - (int)( maxv[n+1] * yvscale); offGraphics.drawLine( d[b], y1, d[b+1], y2 ); } offGraphics.setColor( Color.black ); } // draw bead accelerations if (( n < B ) && ( showa )) { xpoints[0] = d[b]; xpoints[1] = d[b]; xpoints[2] = d[b+1]; xpoints[3] = d[b+1]; ypoints[0] = yaccel; ypoints[1] = yaccel - (int)( a[n] * yascale ); ypoints[2] = yaccel - (int)( a[n+1] * yascale ); ypoints[3] = yaccel; offGraphics.setColor( Color.orange ); offGraphics.fillPolygon( xpoints, ypoints, 4); if ( showmaxa ) { y1 = yaccel - (int)( maxa[n] * yascale); y2 = yaccel - (int)( maxa[n+1] * yascale); offGraphics.drawLine( d[b], y1, d[b+1], y2 ); } offGraphics.setColor( Color.black ); } // draw coriolis forces if (( n < B ) && ( showc ) ) { xpoints[0] = d[b]; xpoints[1] = d[b]; xpoints[2] = d[b+1]; xpoints[3] = d[b+1]; ypoints[0] = ycoriolis; ypoints[1] = ycoriolis - (int)( c[n] * ycscale ); ypoints[2] = ycoriolis - (int)( c[n+1] * ycscale ); ypoints[3] = ycoriolis; offGraphics.setColor( Color.green ); offGraphics.fillPolygon( xpoints, ypoints, 4); if ( showmaxc ) { y1 = ycoriolis - (int)( maxc[n] * ycscale); y2 = ycoriolis - (int)( maxc[n+1] * ycscale); offGraphics.drawLine( d[b], y1, d[b+1], y2 ); } offGraphics.setColor( Color.black ); } // draw radial counterthrust forces if (( n < B ) && ( showr )) { xpoints[0] = d[b]; xpoints[1] = d[b]; xpoints[2] = d[b+1]; xpoints[3] = d[b+1]; ypoints[0] = yradial; ypoints[1] = yradial - (int)( fr[n] * yrscale ); ypoints[2] = yradial - (int)( fr[n+1] * yrscale ); ypoints[3] = yradial; offGraphics.setColor( Color.magenta); offGraphics.fillPolygon( xpoints, ypoints, 4); if ( showmaxr ) { y1 = yradial - (int)( maxr[n] * yrscale); y2 = yradial - (int)( maxr[n+1] * yrscale); offGraphics.drawLine( d[b], y1, d[b+1], y2 ); } offGraphics.setColor( Color.black ); } s = "" + (int)( RMAX / 1000.0) + " km " + elevatorName; s = s + " Bead mass " + (int)mb + " kg"; s = s + " Tie len " + (int)(ltie/1000.0) + " km"; s = s + " XsectA " + (float)atie +" m2"; s = s + " YM " + (int)(ymod/(1E6)) + " GPa"; offGraphics.drawString( s, 2, 12 ); s = "" + "Counterweight " + (int)m[1] + " kg "; s = s + " Max radial velocity " + VMAX + " m/s"; s = s + " Lowest tie tension " + (int)t[LOWEST] + " N "; offGraphics.drawString( s , 2, 24 ); s = "" + (int)TIME + " s"; val = ((double)((int)(DT * 100000.0))) / 100000.0; s = s + " DT " + val; s = s + " Brake power " + (int)( brakePowerOutput / 1000000.0 ) + "MW"; offGraphics.drawString( s , 2, 36 ); b++; } /* draw offGraphics into Graphics */ g.drawImage( offImage, 0, 0, this ); } public void stop() { testThread = null; } }