/** Alternative Relativity Demonstrator by Robert John Morton (all rights reserved) Belo Horizonte-MG 31 July 2006 Produced (concept to full release) in 5 afternoons. */ /* HTML call for this applet: // preselection of default module speed // annotations 0=English, 1=Portuguese */ import java.awt.*; import java.lang.System; import java.awt.event.*; // for the new-fangled 1.1 event handling public class altrel extends java.applet.Applet implements Runnable { private int ds = 0, // default speed selection I = 7, // number of buttons (check boxes) ls = 0, // language selection parameter 0=English 1=Português mp = 6; // size of the module/phantom references array private long //cycle perids of the applet according to warp speed P[] = { 20, 20, 20, 20, 20, 12, 7 }, p = 20, // applet's prescribed cycle period (milliseconds) T = 0, // System Time at end of last cycle dT = 0, // change in System Time between last cycle and this cycle st = 10; // required sleep time (P - dT) private double // velocity selection options MV[] = { 0.1, 0.5, 0.8, 1.0, 1.2, 5.0, 9.9 }, mv, // (default) module velocity - outbound mvr, // module velocity - return pv, // phantom velocity - outbound pvr, // phantom velocity - return TDo = 0, // time dilation of phantom's clock - outbound TDr = 0; // time dilation of phantom's clock - return private boolean cf = true; // true means new velocity selected private String S[] = new String[6]; // array for localized annotations private Font font; // a font reference for annotations private FontMetrics fm; // dimensions of letters etc of chosen font private Label L; // reference for button group heading private CheckboxGroup G; // reference for this checkbox group // references to individual checkboxes within it private Checkbox cb0, cb1, cb2, cb3, cb4, cb5, cb6; private Checkbox B[]; // array to hold the check box references private velbut IL[]; // array for "item listener" references // for references to instances of journey class private journey MP[] = new journey[mp]; //declare a thread reference variable private volatile Thread AltRelThread; public void init() { // INITIALIZE THE APPLET String SA[][] = { {"Velocity Selector:", "Velocidade:"}, {"Module Velocity", "Velocidade do Módulo"}, {"Phantom Velocity", "Velocidade do Fantasma"}, {"Phantom's Clock Speed", "Relógio do Fantasma"}, {"Outbound", "Ao exterior"}, {"Return", "Retorno"} }, SB[] = {"0.1", "0.5", "0.8", "1.0", "1.2", "5.0", "9.9"}; ls = Integer.valueOf(getParameter("lang")).intValue(); for(int i = 0; i < 6; i++) S[i] = SA[i][ls]; // localize the annotations if(ls == 1) // substitute comma for point in Portuguese version for(int i = 0; i < 7; i++) SB[i] = SB[i].replace('.', ','); ds = Integer.valueOf(getParameter("selvel")).intValue(); p = P[ds]; // default cycle period mv = MV[ds]; // (default) module velocity - outbound boolean DS[] = { false, false, false, false, false, false, false }; DS[ds] = true; // default speed received from HTML call parameter B = new Checkbox[I]; // array for radio button references IL = new velbut[I]; // array for Item Listener references L = new Label(S[0], Label.LEFT); G = new CheckboxGroup(); cb0 = new Checkbox(SB[0] + " c", G, DS[0]); cb1 = new Checkbox(SB[1] + " c", G, DS[1]); cb2 = new Checkbox(SB[2] + " c", G, DS[2]); cb3 = new Checkbox(SB[3] + " c", G, DS[3]); cb4 = new Checkbox(SB[4] + " c", G, DS[4]); cb5 = new Checkbox(SB[5] + " c", G, DS[5]); cb6 = new Checkbox(SB[6] + " c", G, DS[6]); add(L); // add the title label to the applet panel IL = new velbut[I]; // create array for "velbut.class" references B[0] = (Checkbox)add(cb0); IL[0] = new velbut(0, this); B[0].addItemListener(IL[0]); B[1] = (Checkbox)add(cb1); IL[1] = new velbut(1, this); B[1].addItemListener(IL[1]); B[2] = (Checkbox)add(cb2); IL[2] = new velbut(2, this); B[2].addItemListener(IL[2]); B[3] = (Checkbox)add(cb3); IL[3] = new velbut(3, this); B[3].addItemListener(IL[3]); B[4] = (Checkbox)add(cb4); IL[4] = new velbut(4, this); B[4].addItemListener(IL[4]); B[5] = (Checkbox)add(cb5); IL[5] = new velbut(5, this); B[5].addItemListener(IL[5]); B[6] = (Checkbox)add(cb6); IL[6] = new velbut(6, this); B[6].addItemListener(IL[6]); font = new java.awt.Font("System", Font.PLAIN, 12); fm = getFontMetrics(font); // get the metrics (pixel dimensions of } // height, leading etc.) for this font void wiper(Graphics g) { g.setColor(Color.lightGray); // set to applet background colour g.fillRect(10, 40, 500, 16); // wipe the graphics field's display area g.fillRect(85, 75, 420, 40); // wipe the name field's display area g.setColor(Color.black); // set module colour g.setFont(font); // set up the annotation font showFigures(g,90,mv,pv,TDo); // display the outbound journey figures showFigures(g,110,mvr,pvr,TDr); // display the return journey figures } // set up graphics & repaint after browser events public void paint(Graphics g) { wiper(g); g.drawString(S[1], 90, 70); // display the localized annotations g.drawString(S[2], 220, 70); g.drawString(S[3], 370, 70); g.drawString(S[4], 10, 90); g.drawString(S[5], 10, 110); } public void update(Graphics g) { // UPDATE THE DISPLAY if (cf) { // if a new velocity has been selected cf = false; // cancel the velocity change-flag // module's return velocity=reverse of outbound velocity mvr = -mv; // phantom's velocity (as fraction of module velocity) outbound pv = 1 / (1 + mv); // compute time dilation on outward journey TDo = pv; // phantom's velocity (as fraction of module velocity) inbound pvr = 1 / (1 + mvr); TDr = pvr; // compute time dilation on return journey wiper(g); for(int i = 0; i < mp; i++) // kill all journey objects MP[i] = null; // spawn a new journey object (generate a new one) MP[0] = new journey(mv,pv,pvr); } // for all possible module/phantom journeys for(int i = 0; i < mp; i++) { journey r = MP[i]; // reference to this journey instance if (r != null) { // if this jouney is still in progress r.update(g); // update this journey if(r.getmh()) // if module has reached home on return journey if(!r.getnl()) { // if new journey has not yet been launched int k = i; // create a cyclic index variable // for all possible journey objects for(int j = 0; j < mp; j++) { if(++k >= mp) // cycle round to the start k = 0; // of the references array // if no live journey exists in this element if (MP[k] == null) { MP[k] = new journey(mv,pv,pvr); // spawn a new journey object r.setnl(); // signal that new launch has been done break; // stop seach for an element with a null reference } } } else if(r.getah()) // if both phantoms have arrived, MP[i] = null; // kill this journey } } } private void showFigures(Graphics g, int l, double m, double p, double t) { g.setColor(Color.black); // set text colour String sm = "" + m + " c", // make string version of module velocity sp = "" + p * m + " c", // phantom velocity st = "" + t; // time dilation if(ls == 1) { // subst , for . in Portuguese version sm = sm.replace('.', ','); sp = sp.replace('.', ','); st = st.replace('.', ','); } g.drawString(sm,90,l); // display the module velocity g.drawString(sp,220,l); // display the phantom velocity g.drawString(st,370,l); // display the time dilation } public void run() { // set applet's thread as system's current thread Thread thisThread = Thread.currentThread(); // while the AltRel Applet's thread remains alive... while (AltRelThread == thisThread) { dT = System.currentTimeMillis() - T; // time since last cycle if(dT < p) st = p - dT; else st = 0; // compute sleep time // sleep while allowing browser events to break thread try {thisThread.sleep(st);} /* Triggers a 'reset' if applet is restarted happens if you return to to applet's HTML page triggers re-start of module/phantom journeys. */ catch (InterruptedException e) { cf = true; } // Note current System Time ready for next cycle T = System.currentTimeMillis(); // sets up a call to update() bringing the Graphics environment with it repaint(); } } public void start() { // Start program thread by AltRelThread = new Thread(this); // creating the thread object AltRelThread.start(); // and starting it running T = System.currentTimeMillis(); // Note System Time at start of session } // [returns a call to run()] public void stop() { // kill this applet's thread AltRelThread = null; } void selectVelocity(int i) { // CALLED BY THE LISTENER CLASS BELOW... mv = MV[i]; // set up the newly selected velocity p = P[i]; // cycle period to best illustrate this velocity cf = true; // set the change flag to re-start the journeys repaint(); // re-initialize the display - sets up call to update() } // (CALLED BY EVENT LISTENER CLASS BELOW) } // LISTENS FOR EVENTS FROM VELOCITY SELECTOR BUTTONS class velbut implements ItemListener { int id; //one of the above events altrel ap; //application that called: always the above applet! public velbut(int id, altrel ap) { // constructor for a new checkbox event this.id = id; // set id number of this instance of 'velbut' this.ap = ap; // set the reference to this instance of the applet } // from which it came. (only one instance anyway). // a checkbox event has occurred from checkbox 'id' public void itemStateChanged(ItemEvent e) { switch(id) { // communicate the selection to the above applet. case 0: ap.selectVelocity(0); break; case 1: ap.selectVelocity(1); break; case 2: ap.selectVelocity(2); break; case 3: ap.selectVelocity(3); break; case 4: ap.selectVelocity(4); break; case 5: ap.selectVelocity(5); break; case 6: ap.selectVelocity(6); break; } } } class journey { //HANDLES ONE ROUND TRIP OF A MODULE AND ITS PHANTOM private boolean mh = false, // true means inbound module has arrived back home pa = false, // true means outbound phantom has reached distant star ph = false, // true means inbound phantom has reached home nl = false, // new journey not yet launched from this instance bx1 = false, // true = outbound module has been drawn on the screen bx2 = false, // true = inbound module has been drawn on the screen bd1 = false, // true = outbound phantom has been drawn on the screen bd2 = false, // true = inbound phantom has been drawn on the screen flashed = false, // true= flash of return phantom displayed (1.0c only) wiped = false, // true=flash has been wiped (for 1.0c only) ftt = true; // true=first time through private int BX = 10, // horizontal bias for start of graph Xmax = 500, // maximum extent of journey (in pixels) Y1 = 40, // top point of trace lines Y2 = 55, // bottom point of trace lines x1 = 0, // last time's screen x-coordinate of outbound module x2 = 0, // last time's screen x-coordinate of inbound module d1 = 0, // last time's screen x-coordinate of outbound phantom d2 = 0; // last time's screen x-coordinate of inbound phantom private double X1 = 0, // outbound distance of module from observer X2 = Xmax, // return distance of module from observer D1 = 0, // distance of outbound phantom from observer D2 = 0, // distance of inbound phantom from observer mv, // module velocity - outbound mvr, // module velocity - return pv, // phantom velocity - outbound pvr; // phantom velocity - return journey(double a, double b, double c) { // JOURNEY INSTANCE CONSTRUCTOR mv = a; mvr = -a; pv = b; pvr = c; //outbound and return velocities } // for module and its phantom // these methods allow applet to access this class's flags boolean getmh() { return (mh); } boolean getah() { return (pa && ph); } boolean getnl() { return (nl); } void setnl() { nl = true; } // allows applet to set // "new launch expedited" flag herein void update(Graphics g) { g.setColor(Color.lightGray); // set wipe colour if(mv == 1 && !wiped) // if selected velocity is c & flash not yet wiped if(ftt) // if first time through ftt = false; // don't wipe flash but kill ftt flag else { // else g.fillRect(10,30,500,16); // wipe the graphics field's display area wiped = true; // and signal that it has been wiped } else { if(bx1) { // wipe last time's outbound module g.drawLine(x1,Y1,x1,Y2); bx1 = false; } if(bx2) { // wipe last time's inbound module g.drawLine(x2, Y1, x2, Y2); bx2 = false; } if(bd1) { // wipe last time's outbound phantom g.drawLine(d1, Y1, d1, Y2); bd1 = false; } if(bd2) { // wipe last time's inbound phantom g.drawLine(d2, Y1, d2, Y2); bd2 = false; } } if(D1 < Xmax) { // if outbound phantom not yet reached the distant star... if(++X1 < Xmax) { // if outbound module not yet reached distant star g.setColor(Color.black); // set module colour x1 = BX + (int)X1; // compute its window x coordinate g.drawLine(x1,Y1,x1,Y2); // display outbound module line bx1 = true; // 'outbound module has been displayed' } D1 = X1 * pv; // update distance of outbound phantom from observer if(D1 < Xmax && D1 > 0) { // if phantom currently within display area g.setColor(Color.white); // set phantom colour d1 = BX + (int)D1; // compute the phantom's window x-coordinate g.drawLine(d1,Y1,d1,Y2); // display outbound phantom in new position bd1 = true; // 'outbound phantom has been displayed' } } else pa = true; // phantom has arrived at distant star if(X1 > Xmax) { // if the outbound module has already reached the star... X2--; // decrement the return distance if (X2 < Xmax && X2 > 0) { g.setColor(Color.black); //set module colour x2 = BX + (int)X2; //compute its new window x-coordinate g.drawLine(x2, Y1, x2, Y2); //display the inbound module line bx2 = true; //'inbound module has been displayed' } else { mh = true; //module has reached home again if(mv == 1 // if module velocity is c && !flashed) { //and return phantom flash not yet done g.setColor(Color.white); //set to flash colour g.fillRect(10,30,500,16); // flash whole graphics display area flashed = true; // signal that the flash has been done } } D2 = X2 * pvr; // update distance of inbound phantom from observer if(D2 < Xmax && D2 > 0) { // if it is within the display area... g.setColor(Color.white); // set phantom colour d2 = BX + (int)D2; // compute its window x-coordinate g.drawLine(d2, Y1, d2, Y2); // display the inbound phantom bd2 = true; // signal that inbound phantom has been displayed } else ph = true; // else signal that the phantom has reached home again } } } /* This source code is the intellectual property of Robert John Morton PGBR301056356 YE572246C CGPI/DIREX/DPF-V429810-2 CPF01681522667 */