/* * PlanetStats.java * * Class: PlanetStats * Author: Samuel Penn (sam@glendale.org.uk) * Version: 1.00 (17th May 1998) * Purpose: Java version of my original !Planet application * for RISC OS. Calculates useful information about * a planet. * * License: BSD */ import java.applet.*; import java.awt.*; import java.util.*; import java.net.*; import java.io.*; public class PlanetStats extends Applet { GridBagLayout gl; GridBagConstraints gb; Label label; TextField tfStarMass, tfDistance, tfDensity; TextField tfDiameter, tfPeriod, tfPlanetMass; TextField tfSurface, tfEscape, tfRealMass; Button bOkay; Choice chPlanets, chStars; void addLabel(int x, int y, String text) { gb.anchor = gb.EAST; gb.fill = gb.NONE; gb.weightx=gb.weighty=0; gb.gridwidth=gb.gridheight=1; gb.gridx=x; gb.gridy=y; label = new Label(text); gl.setConstraints(label, gb); add(label); } void addLabelL(int x, int y, String text) { gb.anchor = gb.WEST; gb.fill = gb.NONE; gb.weightx=gb.weighty=0; gb.gridwidth=gb.gridheight=1; gb.gridx=x; gb.gridy=y; label = new Label(text); gl.setConstraints(label, gb); add(label); } TextField addTextField(int x, int y, int width, String text) { TextField tf; gb.anchor = gb.WEST; gb.fill = gb.HORIZONTAL; gb.weightx=gb.weighty=1; gb.gridwidth=width; gb.gridheight=1; gb.gridx=x; gb.gridy=y; tf = new TextField(text); gl.setConstraints(tf, gb); add(tf); return tf; } public void init() { gl = new GridBagLayout(); gb = new GridBagConstraints(); setLayout(gl); // Add all the static labels. addLabel(0, 0, "Star mass (solar)"); addLabel(0, 1, "Distance (Mkm)"); addLabel(0, 2, "Density (rd)"); addLabel(0, 3, "Diameter (km)"); addLabel(0, 4, "Period"); addLabelL(0, 5, "Planetary Mass"); addLabelL(1, 5, "Surface Gravity"); addLabelL(2, 5, "Escape Velocity"); // Add the various text fields. gb.insets = new Insets(3, 3, 3, 3); tfStarMass = addTextField(1, 0, 1, "1.0"); tfRealMass = addTextField(2, 0, 1, "2.2e30"); tfDistance = addTextField(1, 1, 1, "150"); tfDensity = addTextField(1, 2, 1, "5.5"); tfDiameter = addTextField(1, 3, 1, "12756"); tfPeriod = addTextField(1, 4, 1, "365d"); tfPlanetMass = addTextField(0, 6, 1, "5.97e24"); tfSurface = addTextField(1, 6, 1, "1.00"); tfEscape = addTextField(2, 6, 1, "11.18"); // For those text fields which are display only, // set editable flag to be false. tfRealMass.setEditable(false); tfPlanetMass.setEditable(false); tfSurface.setEditable(false); tfEscape.setEditable(false); tfPeriod.setEditable(false); // Now create a 'calculate' button for the user to click. gb.gridx = 2; gb.gridy = 4; gb.fill = gb.HORIZONTAL; bOkay = new Button("Calculate"); gl.setConstraints(bOkay, gb); add(bOkay); // Drop down list of pre-defined star types. addLabelL(3, 0, "Choose a star:"); gb.gridx = 3; gb.gridy = 1; gb.fill = gb.HORIZONTAL; chStars = new Choice(); gl.setConstraints(chStars, gb); add(chStars); chStars.addItem("Sol"); chStars.addItem("Rigel (Supergiant)"); chStars.addItem("Betelgeux (Red Supergiant)"); chStars.addItem("Aldebaran (Red Giant)"); chStars.addItem("Sirius B (White Dwarf)"); chStars.addItem("Wolf 339 (Red Dwarf)"); // Drop down list of pre-defined planet types. addLabelL(3, 2, "Choose a planet:"); gb.gridx = 3; gb.gridy = 3; gb.fill = gb.HORIZONTAL; chPlanets = new Choice(); gl.setConstraints(chPlanets, gb); add(chPlanets); chPlanets.addItem("Mercury"); chPlanets.addItem("Venus"); chPlanets.addItem("Earth"); chPlanets.addItem("Mars"); chPlanets.addItem("Jupiter"); chPlanets.addItem("Saturn"); chPlanets.addItem("Uranus"); // Make sure planets are listed in order from the sun. if (plutoFurthest()) { chPlanets.addItem("Neptune"); chPlanets.addItem("Pluto"); } else { chPlanets.addItem("Pluto"); chPlanets.addItem("Neptune"); } chPlanets.select(2); calculateValues(); } /* * PLUTOFURTHEST * * Returns true if Pluto is the further from the Sun * then Neptune is (they swap in March 1999). * I'm going to be short sighted and not worry about * people using this applet in the 23rd century. */ boolean plutoFurthest() { Date now = new Date(); Date swap = new Date(99, 2, 1); if (now.after(swap)) { return true; } return false; } double planet_mass(double density, double radius) { double mass, volume; volume = (4.0/3.0)*Math.PI*Math.pow(radius, 3); mass = volume*density; return mass; } double surface_gravity(double density, double radius) { double g, mass; mass = planet_mass(density, radius); g = (mass * 6.67e-11); g = g/Math.pow(radius, 2); return g; } double escape_velocity(double density, double radius) { double escape, mass; mass = planet_mass(density, radius); escape = Math.sqrt(2*6.67e-11*mass/radius); return escape; } /* * SECONDSTOSTRING * * Takes a number of seconds, and returns a string * giving that time in seconds, minutes...years. */ String secondsToString(double time) { String str = new String(""); int years=0, days=0, hours=0; int minutes=0, seconds=0; // Seconds. if (time>0) { seconds = (int)(time % 60); time = Math.floor(time/60); } // Minutes. if (time>0) { minutes = (int)(time % 60); time = Math.floor(time/60); } // Hours. We assume exactly 24 hours to a day. if (time>0) { hours = (int)(time % 24); time = Math.floor(time/24); } // Days. We assume exactly 365 days to a year. if(time>0) { days = (int)(time % 365); time = Math.floor(time/365); } // Years. years = (int)time; System.out.println(years+"y "+days+"d "+hours+"h "+ minutes+"m "+seconds+"s"); /* * Now for the complicated stuff. Only output those values * which are non-zero, but also try to be sensible about * accuracy. If total time is in years, don't output anything * less than days etc. */ if (years>100) { // If time is > 100 years, only output years. str = new String(years+" years"); } else if (years>1) { // If years at least 2, output years and days. str = new String(years+"y"); if (days>0) { str = new String(str + " "+days+"d"); } } else if (years>0) { // If only 1 year, then convert to days. str = new String((years*365+days)+" days"); } else if (days>9) { // Less than a year. More than nine days. str = new String(days+"d"); if (hours>0) { str = new String(str+" "+hours+"h"); } } else if (days>1) { // Two days or more. str = new String(days+"d"); if (hours>0) { str = new String(str+" "+hours+"h"); } if (minutes>0) { str = new String(str+" "+minutes+"m"); } } else { // Final case - display right down to seconds. if (days>0) { str = new String(str+days+"d "); } if (hours>0) { str = new String(str+hours+"h "); } if (minutes>0) { str = new String(str+minutes+"m "); } if (seconds>0) { str = new String(str+seconds+"s"); } } return str; } /* * CALCULATE_VALUES * * Read the various user entry fields, and work out the * values of the rest. */ public void calculateValues() { Float value; double starMass, velocity, distance; double v, c, period; double d, r, mass, g; // Mass of star (solar masses). try { value = new Float(tfStarMass.getText()); starMass = value.doubleValue(); } catch (NumberFormatException e) { starMass=0; } // Convert to metric (kg). starMass *= 2e30; tfRealMass.setText(""+starMass+" kg"); // And now multiply by gravitational constant (G) // to find just how much it sucks... starMass *= 6.67e-11; // Distance of planet (Mkm). try { value = new Float(tfDistance.getText()); distance = value.doubleValue(); } catch (NumberFormatException e) { distance=0; } // Convert to metres. distance *= 1e9; // Find period of the planet's orbit. // v = Velocity of the orbit. // c = Circumference of the orbit. v = Math.sqrt(starMass/distance); c = 2 * distance * Math.PI; period = c/v; value = new Float(period); tfPeriod.setText(secondsToString(value.doubleValue())); // Now for planetary mass and gravity. try { value = new Float(tfDiameter.getText()); d = value.doubleValue(); } catch (NumberFormatException e) { d = 0; } r = d*500; // Find radius in metres. v = (Math.pow(r, 3.0))*(4/3)*Math.PI; try { value = new Float(tfDensity.getText()); d = value.doubleValue(); } catch (NumberFormatException e) { d = 0; } mass = v * d * 1000; // Find mass in kg. // Display mass of the planet (kg). tfPlanetMass.setText(""+mass+" kg"); g = surface_gravity(d*1000, r); v = escape_velocity(d*1000, r); tfEscape.setText(""+(v/1000)+" km/s"); tfSurface.setText(""+g+" m/s/s"); } public void selectStar() { switch(chStars.getSelectedIndex()) { case 0: // Sol. tfStarMass.setText("1.0"); break; case 1: // Rigel. tfStarMass.setText("50"); break; case 2: // Betelgeux. tfStarMass.setText("20"); break; case 3: // Aldebaran. tfStarMass.setText("6"); break; case 4: // Sirius B. tfStarMass.setText("1"); break; case 5: // Wolf 339. tfStarMass.setText("0.2"); break; } } public void selectPlanet() { int idx = chPlanets.getSelectedIndex(); // Fudge the index if Pluto is eigth in list. if (idx==7 && !plutoFurthest()) { idx=8; } else if (idx==8 && !plutoFurthest()) { idx=7; } switch (idx) { case 0: // Mercury. tfDistance.setText("57.9"); tfDiameter.setText("4878"); tfDensity.setText("5.5"); break; case 1: // Venus. tfDistance.setText("108.2"); tfDiameter.setText("12104"); tfDensity.setText("5.25"); break; case 2: // Earth. tfDistance.setText("149.5979"); tfDiameter.setText("12756"); tfDensity.setText("5.517"); break; case 3: // Mars. tfDistance.setText("227.94"); tfDiameter.setText("6787"); tfDensity.setText("3.94"); break; case 4: // Jupiter. tfDistance.setText("778.34"); tfDiameter.setText("142200"); tfDensity.setText("1.33"); break; case 5: // Saturn. tfDistance.setText("1427.0"); tfDiameter.setText("119300"); tfDensity.setText("0.71"); break; case 6: // Uranus. tfDistance.setText("2869.6"); tfDiameter.setText("51200"); tfDensity.setText("1.27"); break; case 7: // Neptune. tfDistance.setText("4496.7"); tfDiameter.setText("49500"); tfDensity.setText("1.77"); break; case 8: // Pluto. tfDistance.setText("5900"); tfDiameter.setText("2290"); tfDensity.setText("2.1"); break; } } /* * HELP * * Displays useful help information on the applet. */ public void help() { URL url; String file; try { file = getDocumentBase().toExternalForm(); System.out.println("DocumentBase = "+file); file = file.substring(0, file.lastIndexOf("/")); System.out.println("Path of document = "+file); file = new String(file+"/help.html"); System.out.println("Help document = "+file); url = new URL(file); } catch (MalformedURLException e) { System.out.println("Malformed help URL"); return; } getAppletContext().showDocument(url); } /* * ACTION * * General event handling. */ public boolean action(Event e, Object arg) { if (e.target == bOkay) { calculateValues(); return true; } else if (e.target == chStars) { selectStar(); calculateValues(); return true; } else if (e.target == chPlanets) { selectPlanet(); calculateValues(); return true; } return false; } }