//************************************************************************// // -------- kepler2.java ------------ // // // // Java applet kepler2.java to animate elliptical orbits using Kepler's // // Laws. Compilation (javac -O kepler.java) produces 4 class files: // // kepler2.class, barSlider.class, barSliderV.class, widePanel.class // // The program may then be implemented from an HTML file containing // // // // // // Your browser doesn't support JAVA---sorry! // // // // // // assuming the two class files are in the same directory as the // // HTML file (otherwise a complete path to the class files must be // // specified with a codebase=path specification in the applet tag---see // // http://csep10.phys.utk.edu/guidry/java/codebase_spec.html for more // // detail on the use of the codebase specification). // // // // Mike Guidry, Jan. 12, 1998 // // guidry@utk.edu // // // //************************************************************************// import java.applet.*; import java.awt.*; import java.net.*; import java.lang.*; public class kepler2 extends Applet implements Runnable { barSlider slide1; barSliderV slide2; Button lineOn; Button orbitOn; Button infoOn; static final int nsteps = 150; // Time steps per revolution static final int pixelWidth = 325; // Width of ellipse in pixels static final int xoff = 10; // x offset for plot static final int yoff = 30; // y offset for plot int delay = 5; // speed control double zoom = 1.0; // Conversion factors from Kepler natural units to CGS // and some basic constants static final double secyear=3.155815e+7; static final double AUcm = 1.496e+13; static final double Msolar = 1.989e+33; static final double G = 6.67259e-8; // Input data & associated stuff double e = 0.65; // eccentricity double M1 = 1.0; // mass 1 (solar) double M2 = 1.0; // mass 2 (solar) double M = M1*M2/(M1 + M2); // reduced mass (solar) double ratio = M1/M2; // seesaw mass factor double Mgrams = M * Msolar; // reduced mass (grams) double a = 1.0; // semimajor in AU double acm = AUcm * a; // semimajor in cm // double pixelScale = (double)pixelWidth/a/2.0; // Scale AU --> pixels double maxwidth = a*(ratio + 1.0)*(1. + e); // Max star separation double pixelScale = zoom * (double)pixelWidth/maxwidth; // Scale AU --> pixels int apixel = (int)(pixelScale*a); // semimajor in pixels double b = Math.sqrt(a*a*(1.0-e*e)); // semiminor in AU int bpixel = (int)(pixelScale*b); // semiminor in pixels double P; // period in years double Psec; // period in sec double r = a*(1.0 - e); // r from focus in AU double rcm = acm*(1.0 - e); // r from focus in cm double theta = 0.0; // angle from focus double dtheta; // angle increment double t = 0.0; // time double dt; // time increment double elast = e; // preceding value of e double alast = a; // preceding value of a double Mlast = M; // preceding value of M double zoomlast = zoom; // preceding value of M int xshift; // java coordinate shift int yshift; // java coordinate shift int tcounter=0; // time print interval double timeprint=0.0; // printed time Image sun; Image planet; int sizeSun; int sizePlanet; int x = 0; int y = 0; int xprime = 0; int yprime = 0; Color c1 = new Color(0x000000); Color c2 = new Color(0xffffff); Font font = new Font("Helvetica", Font.PLAIN, 10); FontMetrics fontFontMetrics = getFontMetrics(font); Image offscreen; int imagewidth, imageheight; Thread animator = null; boolean please_stop = false; boolean show_orbit = true; boolean psunLine = false; boolean showInfo = false; public void init() { URL codeBase = getCodeBase(); sun = getImage(codeBase,"siriusA.jpg"); planet = getImage(codeBase,"siriusB.jpg"); // Measure size of images being animated. We need this // information later if we do clipping, and for positioning. // // ----------------------------------------------------------------- // Following two methods seem to work with appletviewer, but // not with browsers (?). When run under browsers they tend to // return -1 for the size. // // sizeSun = sun.getWidth(this); // sizePlanet = planet.getWidth(this); // // Replaced with the hard-wired sizes below. // ------------------------------------------------------------------ sizeSun = 28; // hardwired image size sizePlanet = 15; // hardwired image size // Calculate period in years from Kepler's 3rd Law and // convert to CGS units (seconds). Then calculate the length of // a timestep in seconds. P = Math.sqrt(a*a*a/M); Psec = secyear * P; dt = Psec/((double) nsteps); // set negative for counterclockwise // Lay out the GUI Display and implement the corresponding // event handlers. First define some colors and fonts and // Lay out a set of panels. Will use BorderLayout to lay out // north, south, east, and west panels framing the plot region. // Only north and south panels will get widgets. The event // handlers for the widgets are contained in the method // action (Event event, Object arg) defined below, except for // the slidebar, which has its own class barSlider with its own // event handler. Color panelbg=Color.cyan.darker(); Color panelfg=Color.white; Color buttonfg=Color.black; Font buttonFont = new Font ("Helvetica",Font.BOLD, 11); setLayout(new BorderLayout()); Panel pt = new Panel(); add("North",pt); pt.setBackground(panelbg); Panel pb = new Panel(); add("South",pb); pb.setBackground(panelbg); widePanel pl = new widePanel(); add("West",pl); pl.setBackground(panelbg); Panel pr = new Panel(); add("East",pr); pr.setBackground(panelbg); // Now construct GUI components for the top and bottom panels // Define a toggle switch to turn planet-sun line on or off lineOn = new Button (" Lines "); lineOn.setBackground(Color.pink); lineOn.setForeground(Color.black); // Define a toggle switch to turn orbit path on or off orbitOn = new Button (" No Orbit "); orbitOn.setBackground(Color.pink); orbitOn.setForeground(Color.black); // Define a toggle switch to turn info labels on or off infoOn = new Button (" Info "); infoOn.setBackground(Color.pink); infoOn.setForeground(Color.black); // Choice button to set speed of orbital motion Choice setSpeed = new Choice(); setSpeed.addItem("Slow"); setSpeed.addItem("Med"); setSpeed.addItem("Fast"); setSpeed.addItem("Max"); setSpeed.setBackground(Color.pink); setSpeed.setForeground(Color.black); setSpeed.select("Fast"); // Choice button to set mass in solar units Choice setZoom = new Choice(); setZoom.addItem("Zoom=0.25"); setZoom.addItem("Zoom=0.50"); setZoom.addItem("Zoom=0.75"); setZoom.addItem("Zoom=1.00"); setZoom.addItem("Zoom=1.25"); setZoom.addItem("Zoom=1.50"); setZoom.addItem("Zoom=1.75"); setZoom.addItem("Zoom=2.00"); setZoom.addItem("Zoom=3.00"); setZoom.setBackground(Color.pink); setZoom.setForeground(Color.black); setZoom.select("Zoom=1.00"); // select item for default display // Choice button to set semimajor axis in AU Choice seta = new Choice(); seta.addItem("a=0.39"); seta.addItem("a=0.72"); seta.addItem("a=1.00"); seta.addItem("a=1.52"); seta.addItem("a=2.00"); seta.addItem("a=3.00"); seta.addItem("a=4.00"); seta.addItem("a=5.00"); seta.addItem("a=5.20"); seta.addItem("a=9.54"); seta.addItem("a=10.0"); seta.addItem("a=19.2"); seta.addItem("a=25.0"); seta.addItem("a=30.1"); seta.addItem("a=39.5"); seta.addItem("a=50.0"); seta.addItem("a=75.0"); seta.setBackground(Color.pink); seta.setForeground(Color.black); seta.select(2); // select item #3 (count from 0) // Set a FlowLayout for the top panel, set some colors, // and then add the components for the top panel pt.setLayout(new FlowLayout(FlowLayout.CENTER,10,8)); pt.setForeground(panelfg); pt.setBackground(panelbg); pt.setFont(buttonFont); pt.add(lineOn); pt.add(orbitOn); pt.add(infoOn); pt.add(setZoom); pt.add(seta); pt.add(setSpeed); // Add the slidebar and its labels to the bottom panel. // The class barSlider has its own GridLayout manager pb.add(slide1=new barSlider((int)(e*100.),0,90)); pl.add(slide2=new barSliderV(491,491,1,500)); } // --------------------------------------------------------------------- // Add a method to deal with processing GUI events // (buttons, textareas, checkboxes, ... Slidebar events are handled in // a separate class with its own event handler---see class barSlider). // General mousedown event to toggle animation on an off is handled in // the separate method mouseDown defined below. // --------------------------------------------------------------------- public boolean action(Event event, Object arg) { Label flag; String s; /* --- Comment TextField Actions out ----------------------- // Process TextField Actions if(event.target instanceof TextField) { s=textfield1.getText(); showStatus("TextField Action: "+s +" was the value"); // TextField processing actions go here // //start(); } --- End of commented out section ------------------------- */ // Process Button Actions. The button pushed is identified by // its label (the text on its face). The showStatus command // just displays a message in the status line that button was pushed. // These buttons are set up as 2-state (toggles). Thus, pushing one // toggles a boolean variable and also toggles the text on the // button face. if(event.target instanceof Button) { if(arg == " Lines ") { showStatus("Button Action: "+arg+" pushed"); psunLine = true; // toggle Boolean lineOn.setLabel(" No Lines "); // toggle label } if(arg == " No Lines ") { showStatus("Button Action: "+arg+" pushed"); psunLine = false; // toggle Boolean lineOn.setLabel(" Lines "); // toggle label } if(arg == " Orbit ") { showStatus("Button Action: "+arg+" pushed"); show_orbit = true; // toggle Boolean orbitOn.setLabel(" No Orbit "); // toggle label } if(arg == " No Orbit ") { showStatus("Button Action: "+arg+" pushed"); show_orbit = false; // toggle Boolean orbitOn.setLabel(" Orbit "); // toggle label } if(arg == " Info ") { showStatus("Button Action: "+arg+" pushed"); showInfo = true; // toggle Boolean infoOn.setLabel(" No Info "); // toggle label } if(arg == " No Info ") { showStatus("Button Action: "+arg+" pushed"); showInfo = false; // toggle Boolean infoOn.setLabel(" Info "); // toggle label } } /* --- Comment Checkbox template out for now ---------------- // Process Checkbox actions if(event.target instanceof Checkbox) { Checkbox checkbox=(Checkbox)event.target; String label=checkbox.getLabel(); if(label == "Yes") { showStatus("Checkbox Action: Checkbox=Yes"); psunLine=true; } if(label == "No") { showStatus("Checkbox Action: Checkbox=No"); psunLine=false; } // stop(); // start(); } --- End of commented out section -------------------------- */ // Process Choice Menu actions if(event.target instanceof Choice) { if(arg == "Slow") { showStatus("Choice Action: Choice=Slow"); delay = 100; } if(arg == "Medium") { showStatus("Choice Action: Choice=Medium"); delay = 30; } if(arg == "Fast") { showStatus("Choice Action: Choice=Fast"); delay = 10; } if(arg == "Max") { showStatus("Choice Action: Choice=Fast"); delay = 5; } if(arg == "Zoom=0.25") { showStatus("Choice Action: Choice "+arg); zoom = 0.25; } if(arg == "Zoom=0.50") { showStatus("Choice Action: Choice "+arg); zoom = 0.5; } if(arg == "Zoom=0.75") { showStatus("Choice Action: Choice "+arg); zoom = 0.75; } if(arg == "Zoom=1.00") { showStatus("Choice Action: Choice "+arg); zoom = 1.; } if(arg == "Zoom=1.25") { showStatus("Choice Action: Choice "+arg); zoom = 1.25; } if(arg == "Zoom=1.50") { showStatus("Choice Action: Choice "+arg); zoom = 1.5; } if(arg == "Zoom=1.75") { showStatus("Choice Action: Choice "+arg); zoom = 1.75; } if(arg == "Zoom=2.00") { showStatus("Choice Action: Choice "+arg); zoom = 2.; } if(arg == "Zoom=3.00") { showStatus("Choice Action: Choice "+arg); zoom = 3.; } if(arg == "a=0.39") { showStatus("Choice Action: Choice "+arg); a = 0.3871; } if(arg == "a=0.72") { showStatus("Choice Action: Choice "+arg); a = 0.7233; } if(arg == "a=1.00") { showStatus("Choice Action: Choice "+arg); a = 1.; } if(arg == "a=1.52") { showStatus("Choice Action: Choice "+arg); a = 1.5237; } if(arg == "a=2.00") { showStatus("Choice Action: Choice "+arg); a = 2.; } if(arg == "a=3.00") { showStatus("Choice Action: Choice "+arg); a = 3.; } if(arg == "a=4.00") { showStatus("Choice Action: Choice "+arg); a = 4.; } if(arg == "a=5.00") { showStatus("Choice Action: Choice "+arg); a = 5.; } if(arg == "a=5.20") { showStatus("Choice Action: Choice "+arg); a = 5.2028; } if(arg == "a=9.54") { showStatus("Choice Action: Choice "+arg); a = 9.5388; } if(arg == "a=10.0") { showStatus("Choice Action: Choice "+arg); a = 10.; } if(arg == "a=19.2") { showStatus("Choice Action: Choice "+arg); a = 19.1914; } if(arg == "a=25.0") { showStatus("Choice Action: Choice "+arg); a = 25.; } if(arg == "a=30.1") { showStatus("Choice Action: Choice "+arg); a = 30.0611; } if(arg == "a=39.5") { showStatus("Choice Action: Choice "+arg); a = 39.5294; } if(arg == "a=50.0") { showStatus("Choice Action: Choice "+arg); a = 50.; } if(arg == "a=75.0") { showStatus("Choice Action: Choice "+arg); a = 75.; } // stop(); // start(); } return true; } //---- End action method ----// // Method to toggle stop and start of animation on mouse clicks. // Display prompts and mousedown coordinates in status bar public boolean mouseDown(Event e, int x, int y) { // if running, stop it. Otherwise, start it. // Only accept clicks within rectangle defined by // outer if statement. if(x > 18 && x<440 && y>47 && y<312) { // rectangle for mousedown if (animator != null) { please_stop = true; showStatus("mousedown: x="+x+" y="+y+" Click to Restart"); } else { showStatus("mousedown: x="+x+" y="+y+" Click to Stop"); please_stop = false; start(); } } return false; } // Method to start the animation public void start() { e = barSlider.slideval; animator = new Thread(this); animator.start(); } // Method to stop the animation public void stop() { if (animator != null) animator.stop(); animator = null; } // Method to draw the applet plot background and to update // quantities calculated using e, M, or a if these quantities // change because of input from the GUI widgets void drawBackground(Graphics gr, Color c1) { e = barSlider.slideval; M1 = barSliderV.slideval; M2 = barSliderV.slideval2; M = M1*M2/(M1 + M2); // reduced mass // if(M1 >= M2) { ratio = M2/M1; } // else { ratio = M1/M2; } // ratio = seesaw mass factor ratio = M1/M2; if(e != elast || a != alast || M != Mlast || zoom != zoomlast) { // GUI input has changed acm = AUcm * a; maxwidth = a*(ratio + 1.0)*(1. + e); pixelScale = zoom * (double)pixelWidth/maxwidth; //System.out.println("zoom="+zoom+" pixelScale="+pixelScale); // pixelScale = (double)pixelWidth/a/2.0; apixel = (int)(pixelScale*a); b = Math.sqrt(a*a*(1.0-e*e)); bpixel = (int)(b*pixelScale); Mgrams = M * Msolar; P = Math.sqrt(a*a*a/M); Psec = secyear * P; dt = Psec/((double) nsteps); // Set negative for counterclockwise if(e != elast){t=0.0;} // Reset time if e has changed } Dimension size = this.size(); int w = size.width; int h = size.height; gr.setColor(c1); gr.fillRect(0, 0, w, h); // xshift = w/2 + (int)(e*a*pixelScale) + xoff; xshift = w/2 + xoff; yshift = h/2 +yoff; gr.setColor(Color.white); // gr.drawOval(xshift-3, yshift-3, 6, 6); // Center of Mass gr.drawLine(xshift-2, yshift-2, xshift+2, yshift+2); // Center of Mass gr.drawLine(xshift-2, yshift+2, xshift+2, yshift-2); // Center of Mass // gr.drawImage(sun, xshift - sizeSun/2, yshift - sizeSun/2, this); if (show_orbit == true){ gr.setColor(Color.gray); // gr.drawOval(w/2-apixel+xoff, yshift-bpixel, 2*apixel, 2*bpixel); // Draw the ellipses int xleft = w/2-apixel-(int)(e*a*pixelScale)+xoff; gr.drawOval(xleft, yshift-bpixel, 2*apixel, 2*bpixel); int apixelpr = (int)(a*ratio*pixelScale); int bpixelpr = (int)(b*ratio*pixelScale); // int xright = xleft + (int)(e*a*(1.+ratio)*pixelScale); int xright = xleft + (int)(e*a*(1.+ratio)*pixelScale)+apixel-apixelpr; //System.out.println("apr="+apixelpr+" bpr="+bpixelpr+" a="+apixel+" b="+bpixel); gr.drawOval(xright, yshift-bpixelpr, 2*apixelpr, 2*bpixelpr); // gr.drawOval(w/2-apixel+(int)(e*a*pixelScale)+xoff, // yshift-bpixel, 2*apixel, 2*bpixel); } int xlc = 60; // offset of left printed quantities from left axis gr.setFont(font); gr.setColor(Color.cyan); gr.drawString("a(1) = "+decimalPlace(2,a)+" AU",xlc,60); gr.drawString("a(2) = "+decimalPlace(2, ratio*a)+" AU",xlc+100,60); gr.drawString("M(1) = "+decimalPlace(2,M1)+" solar",xlc,74); gr.drawString("M(2) = "+decimalPlace(2,M2)+" solar",xlc+100,74); gr.drawString("M = "+decimalPlace(2,M)+" solar",xlc,88); gr.drawString("e = "+decimalPlace(2,e),xlc+100,88); gr.drawString("Period = "+decimalPlace(2,P)+" yr",xlc+200,60); // Print a scale legend int scalex = 375; int scaley = 320; int scalepix = pixelWidth/4; gr.setFont(font); double scalewid = ( (double)scalepix/pixelScale ); String scalewidS = decimalPlace(1,scalewid)+" AU"; int scaleoff = fontFontMetrics.stringWidth(scalewidS); gr.drawString(scalewidS, scalex+scalepix/2-scaleoff/2, scaley-10); gr.drawLine(scalex, scaley, scalex+scalepix, scaley); gr.drawLine(scalex, scaley+5, scalex, scaley-5); gr.drawLine(scalex+scalepix, scaley+5, scalex+scalepix, scaley-5); // Print elapsed time every 20 time steps tcounter = (tcounter+1)%21; if (tcounter == 1){ timeprint=t; } // Draw lines to foci of ellipse for each component of binary if (psunLine == true){ // Component 1 gr.setColor(Color.cyan); gr.drawLine(x,y,xshift,yshift); gr.drawLine(x,y,xshift-2*(int)(e*(double)apixel), yshift); gr.fillOval(xshift-2*(int)(e*(double)apixel)-2, yshift-2, 4, 4); gr.fillOval(xshift-2, yshift-2, 4, 4); // Component 2 gr.setColor(Color.red); gr.drawLine(xprime,yprime,xshift,yshift); gr.drawLine(xprime,yprime, xshift+2*(int)(e*a*ratio*pixelScale), yshift); gr.fillOval(xshift+2*(int)(e*a*ratio*pixelScale)-2, yshift-2, 4, 4); } String timestring=decimalPlace(2,timeprint/secyear); gr.setColor(Color.cyan); gr.drawString("Time = "+timestring+" yr",xlc+300,60); gr.drawString("R(1) = "+decimalPlace(2,r)+" AU",xlc+200,74); gr.drawString("R(2) = "+decimalPlace(2,r*ratio)+" AU",xlc+300,74); gr.drawString("R = "+decimalPlace(2,r+r*ratio)+" AU",xlc+200,88); // Display the Info if the switch is toggled if(showInfo == true) { gr.setColor(Color.pink); // label for semimajor axis gr.drawLine(w/2+xoff-apixel, yshift, w/2+xoff, yshift); gr.setFont(font); int xwida = fontFontMetrics.stringWidth("a = x.x AU"); gr.setColor(Color.cyan); gr.drawString("a = "+decimalPlace(2,a)+" AU", (w/2+xoff-apixel/2)-xwida/2, yshift-15); // label for semiminor axis int ywidb = fontFontMetrics.getAscent()/2; gr.drawString("b = "+decimalPlace(2,b)+" AU", w/2+xoff+10, yshift-bpixel/2+ywidb); gr.setColor(Color.pink); gr.drawLine(w/2+xoff, yshift, w/2+xoff, yshift-bpixel); // label for foci gr.setColor(Color.cyan); gr.fillOval(xshift-2*(int)(e*(double)apixel)-2, yshift-2, 4, 4); gr.fillOval(xshift-2, yshift-2, 4, 4); gr.setColor(Color.white); gr.drawLine(xshift, yshift, w/2+xoff, yshift+bpixel/2); gr.drawLine(xshift-2*(int)(e*(double)apixel), yshift, w/2+xoff, yshift+bpixel/2); gr.setColor(Color.cyan); int focwid = fontFontMetrics.stringWidth("Foci"); gr.drawString("Foci", w/2+xoff-focwid/2, yshift+bpixel/2+15); } elast = e; // Old values of e, a, M to test whether alast = a; // widgets have been moved Mlast = M; // Tested at top of this method zoomlast = zoom; } // Method decimalPlace returns string that is string representation of double // with a fixed number of places after the decimal. The number of places // after the decimal is given by the integer "nright" and the double is // passed as the variable "number". Routine assumes number is not in // scientific (e) notation. Presently no check is made to ensure that // this is true. Should be easy to fix that. Also, present version rounds // down integer style. e.g., decimalPlace(2,5.678) returns 5.67 as the // string. // // EXAMPLE USE: String nstring = decimalPlace(nright,number) // EXAMPLE USE: g.drawString("Variable=" + decimalPlace(3,variable),100,200) public String decimalPlace(int nright, double number) { double n=number; String tright2=""; String total=String.valueOf(n); int nperiod=total.indexOf("."); if(nperiod == 0 || nperiod == -1){return total;} String tleft=total.substring(0,nperiod); String tright=total.substring(nperiod); int temp1=0, temp2=nright+1; if(tright.length() > nright) { try{tright2=tright.substring(temp1,temp2);} catch (StringIndexOutOfBoundsException e) { ; } } else { tright2=tright; } return tleft+tright2; } // Draw background and images at their current positions public void paint(Graphics g) { drawBackground(g, c1); g.drawImage(planet, x-sizePlanet/2, y-sizePlanet/2, this); g.drawImage(planet, xprime-sizePlanet/2, yprime-sizePlanet/2, this); // g.drawImage(sun, xprime-sizeSun/2, yprime-sizeSun/2, this); } // Main animator thread. The animation thread is based on // an example from the book _Java in a Nutshell_ by David Flanagan, // and implements both double buffering and clipping techniques to // prevent flickering. However, clipping is presently commented // out. public void run() { while(!please_stop) { Dimension d = this.size(); // Create offscreen image at the right size. if ((offscreen == null) || ((imagewidth != d.width) || (imageheight != d.height))) { // if (offscreen != null) offscreen.flush(); offscreen = this.createImage(d.width, d.height); imagewidth = d.width; imageheight = d.height; } // Set up clipping. We only need to draw within the // old rectangle that needs to be cleared and the new // one that is being drawn. // the old rectangle Rectangle oldrect = new Rectangle(x-sizePlanet/2, y-sizePlanet/2, sizePlanet, sizePlanet); // Update the coordinates for animation. // Update time and theta t = t + dt; // Subtract dt for counterclockwise dtheta = Math.sqrt(G*Mgrams*acm*(1.0 - e*e))*dt/rcm/rcm; theta = theta + dtheta; // Calculate new r relative to focus of ellipse r = a*(1.0 - e*e)/(1.0 + e*Math.cos(theta)); rcm = AUcm * r; // Calculate relative x and y in pixels int xrel = (int)(r * Math.cos(theta) * pixelScale); int yrel = (int)(r * Math.sin(theta) * pixelScale); // Calculate new x and y relative to focus x = xrel + xshift; y = yrel + yshift; // and xprime and yprime for the companion using the seesaw ratio // xprime = -(int)(ratio*(double)xrel); // yprime = -(int)(ratio*(double)yrel); xprime = -(int)(ratio * r * Math.cos(theta) * pixelScale); yprime = -(int)(ratio * r * Math.sin(theta) * pixelScale); xprime = xprime + xshift; yprime = yprime + yshift; // the new rectangle Rectangle newrect = new Rectangle(x-sizePlanet/2, y-sizePlanet/2, sizePlanet, sizePlanet); // Compute the union of the rectangles Rectangle r = newrect.union(oldrect); // Use this rectangle as the clipping region when // drawing to the offscreen image, and when copying // from the offscreen image to the screen. // Clipping is disabled if the two g.clipRect() statements // below are commented out. Clipping allows only the // planet to be redrawn, so if enabled the applet will not // redraw orbits and Sun position and labels when e slider // is changed. Graphics g = offscreen.getGraphics(); // g.clipRect(r.x, r.y, r.width, r.height); // Draw into the off-screen image. paint(g); // Copy it all at once to the screen, using clipping. g = this.getGraphics(); // g.clipRect(r.x, r.y, r.width, r.height); g.drawImage(offscreen, 0, 0, this); // wait then draw it again try { Thread.sleep(delay); } catch (InterruptedException e) { ; } } animator = null; } } // ----------- End class kepler ----------------- // /****************************************************************** // // // // Class barSlider implements a horizontal slidebar for input of // // eccentricity. Class has its own event processor that sets the // // class double variable "slideval" equal to the value of the // // slidebar when it is moved. This variable may then be accessed // // from another class by creating a barSlider object and then // // accessing its slideval field. EXAMPLE: // // // // barSlider bslide = new barSlider(int i, int min, int max); // // double number = bslide.slideval; // // // // The class has its own GridLayout manager implemented so a // // typical GUI would add an instance of the class as a // // component to a panel. EXAMPLE: // // // // barSlider bslide = new barSlider(int i, int min, int max); // // Panel newpanel = new Panel(); // // newpanel.add(bslide); // // // // Variables: // // int i = initial value of slider 1 // // int min = minimum value for slider // // int max = maximum value for sliders // // // // Mike Guidry Feb. 20, 1997 // // // // *******************************************************************/ class barSlider extends Panel { Scrollbar slider; Label value; static double slideval; Font font = new Font("Helvetica", Font.BOLD, 12); kepler kp = new kepler(); // To be able to access decimalPlace method // of the class kepler through kp.decimalPlace public barSlider(int i, int min, int max) { setFont(font); setLayout(new GridLayout(1,3,15,15)); add(value = new Label("e: ",Label.RIGHT)); value.setForeground(Color.black); add(slider = new Scrollbar(Scrollbar.HORIZONTAL, i, 1, min, max)); slider.setBackground(Color.lightGray); add(value = new Label(kp.decimalPlace(1,(double)i/100.),Label.LEFT)); value.setForeground(Color.black); slideval=(double)i/100.; } public boolean handleEvent(Event evt) { if (evt.target.equals(slider)) { int i = slider.getValue(); value.setText(kp.decimalPlace(2,(double)i/100.)); slideval=(double)i/100.; } return true; } // Rescale the preferred size of buttons in the layouts public Dimension preferredSize() { return new Dimension(800, 15); } } // ----- End class barSlider ----- /****************************************************************** // // // // Class barSliderV implements 2 vertical slidebars for input of // // mass. Class has its own event processor that sets the // // class double variable slideval equal to the value of the // // first slidebar when it is moved and slideval2 equal to the value // // of the second slidebar when it is moved. These variables may // // then be accessed from another class by creating a barSliderV // // object and then accessing its slideval and slideval2 fields. // // EXAMPLE: // // // // int i,j,min,max // // barSliderV bslide = new barSliderV(i, j, min, max); // // double number = bslide.slideval; // // double number2 = bslide.slideval2; // // // // The class has its own GridLayout manager implemented so a // // typical GUI would add an instance of the class as a // // component to a panel. EXAMPLE: // // // // barSliderV bslide = new barSliderV(i, j, min, max); // // Panel newpanel = new Panel(); // // newpanel.add(bslide); // // // // Variables: // // int i = initial value of slider 1 // // int j = initial value of slider 2 // // int min = minimum value for sliders (presently same for both) // // int max = maximum value for sliders ( " " " " ) // // // // // // Mike Guidry Feb. 20, 1997 // // // // *******************************************************************/ class barSliderV extends Panel { Scrollbar slider, slider2; Label value1,value2,value3,value4,filler; static double slideval,slideval2; Font font = new Font("Helvetica", Font.PLAIN, 10); kepler kp = new kepler(); // To be able to access decimalPlace method // of the class kepler through kp.decimalPlace public barSliderV(int i, int j, int min, int max) { setFont(font); setLayout(new GridLayout(6,1,0,0)); add(value2 = new Label(kp.decimalPlace(1,(double)(501-i)/10.), Label.CENTER)); value2.setForeground(Color.black); add(slider = new Scrollbar(Scrollbar.VERTICAL, i, 1, min, max)); slider.setBackground(Color.lightGray); add(value1 = new Label("M1",Label.CENTER)); value1.setForeground(Color.black); add(value4 = new Label(kp.decimalPlace(1,(double)(501-j)/10.), Label.CENTER)); value4.setForeground(Color.black); add(slider2 = new Scrollbar(Scrollbar.VERTICAL, i, 1, min, max)); slider2.setBackground(Color.lightGray); add(value3 = new Label("M2",Label.CENTER)); value3.setForeground(Color.black); slideval=(double)(501-i)/10.; slideval2=(double)(501-j)/10.; } public boolean handleEvent(Event evt) { if (evt.target.equals(slider)) { int i = slider.getValue(); value2.setText(kp.decimalPlace(1,(double)(501-i)/10.)); slideval=(double)(501-i)/10.; } if (evt.target.equals(slider2)) { int i = slider2.getValue(); value4.setText(kp.decimalPlace(1,(double)(501-i)/10.)); slideval2=(double)(501-i)/10.; } return true; } // Rescale the preferred size of buttons in the layouts public Dimension preferredSize() { return new Dimension(20,310); } } // ----- End class barSliderV ----- class widePanel extends Panel { // Over-rides the perferredSize() & minimumSize() methods of the Panel class // to allow control of a panel size. Example usage: create an object of // the widePanel class: widePanel lpanel = new widePanel(); // Then the dimensions of lpanel can be controlled by changing the // parameters in the dimension statements below. Otherwise, it has // all the properties of a normal Panel class object. public Dimension preferredSize() { return new Dimension(30, 300); } public Dimension minimumSize() { return new Dimension(30, 300); } }