import java.awt.*; /* A basic extension of the java.applet.Applet class */ import java.awt.*; import java.applet.*; import java.util.Random; public class Binary extends Applet { void blueLuminositySlider_Action(Event event) { lb=blueLuminositySlider.getValue()/100.0; blueLuminosityText.setText(String.valueOf(lb)); repaint(); } void blueLuminosityText_EnterHit(Event event) { try { lb=Double.valueOf(blueLuminosityText.getText()).doubleValue(); if(lb<0.01) { lb=0.01; blueLuminosityText.setText(String.valueOf(lb)); } else if(lb>1.0) { lb=1.0; blueLuminosityText.setText(String.valueOf(lb)); } blueLuminositySlider.setValue( (int) (lb*100) ); repaint(); } catch(Exception e) {} } void redLuminositySlider_Action(Event event) { lr=redLuminositySlider.getValue()/100.0; redLuminosityText.setText(String.valueOf(lr)); repaint(); } void redLuminosityText_EnterHit(Event event) { try { lr=Double.valueOf(redLuminosityText.getText()).doubleValue(); if(lr<0.01) { lr=0.01; redLuminosityText.setText(String.valueOf(lr)); } else if(lr>1.0) { lr=1.0; redLuminosityText.setText(String.valueOf(lr)); } redLuminositySlider.setValue( (int) (lr*100) ); repaint(); } catch(Exception e) {} } // (Sept. 30,1998) After making additions to allow for elliptical orbits we find that // there is an intermittent bug when red star radius gets smaller than blue star redius, // the stars change place ? void redRadiusSlider_Action(Event event) { rr=redRadiusSlider.getValue()/100.0; if(rr+rb>1-e) { rb=1-e-rr; if(rb<0.01) rb=0.01; blueRadiusText.setText(String.valueOf(rb)); blueRadiusSlider.setValue((int) (rb*100)); } redRadiusText.setText(String.valueOf(rr)); repaint(); } void redRadiusText_EnterHit(Event event) { try { rr=Double.valueOf(redRadiusText.getText()).doubleValue(); if(rr<0.01) { rr=0.01; redRadiusText.setText(String.valueOf(rr)); } else if(rr>1.0) { rr=1.0; redRadiusText.setText(String.valueOf(rr)); } redRadiusSlider.setValue( (int) (rr*100) ); if(rr+rb>1-e) { rb=1-e-rr; if(rb<0.01) rb=0.01; blueRadiusText.setText(String.valueOf(rb)); blueRadiusSlider.setValue((int) (rb*100)); } repaint(); } catch(Exception e) {} } void blueRadiusSlider_Action(Event event) { rb=blueRadiusSlider.getValue()/100.0; if(rr+rb>1-e) { rr=1-e-rb; if(rr<0.01) rr=0.01; redRadiusText.setText(String.valueOf(rr)); redRadiusSlider.setValue((int) (rr*100)); } blueRadiusText.setText(String.valueOf(rb)); repaint(); } void blueRadiusText_EnterHit(Event event) { try { rb=Double.valueOf(blueRadiusText.getText()).doubleValue(); if(rb<0.01) { rb=0.01; blueRadiusText.setText(String.valueOf(rb)); } else if(rb>1.0) { rb=1.0; blueRadiusText.setText(String.valueOf(rb)); } blueRadiusSlider.setValue( (int) (rb*100) ); if(rr+rb>1-e) { rr=1-e-rb; if(rr<0.01) rr=0.01; redRadiusText.setText(String.valueOf(rr)); redRadiusSlider.setValue((int) (rr*100)); } repaint(); } catch(Exception e) {} } void blueMassSlider_Action(Event event) { mb=blueMassSlider.getValue(); blueMassText.setText(String.valueOf(mb)); repaint(); } void blueMassText_EnterHit(Event event) { try { mb=Double.valueOf(blueMassText.getText()).doubleValue(); if(mb<1) { mb=1; blueMassText.setText(String.valueOf(mb)); } else if(mb>100) { mb=100; blueMassText.setText(String.valueOf(mb)); } blueMassSlider.setValue((int)mb); repaint(); } catch(Exception e) {} } void redMassSlider_Action(Event event) { mr=redMassSlider.getValue(); redMassText.setText(String.valueOf(mr)); repaint(); } void redMassText_EnterHit(Event event) { try { mr=Double.valueOf(redMassText.getText()).doubleValue(); if(mr<1) { mr=1; redMassText.setText(String.valueOf(mr)); } else if(mr>100) { mr=100; redMassText.setText(String.valueOf(mr)); } redMassSlider.setValue((int)mr); repaint(); } catch(Exception e) {} } void inclinationSlider_Action(Event event) { inc=inclinationSlider.getValue()-90; inclinationText.setText(String.valueOf(inc)); repaint(); } void inclinationText_EnterHit(Event event) { try { inc=Double.valueOf(inclinationText.getText()).doubleValue(); if(inc<-90) { inc=-90; inclinationText.setText(String.valueOf(inc)); } else if(inc>90) { inc=90; inclinationText.setText(String.valueOf(inc)); } inclinationSlider.setValue((int)(inc+90)); repaint(); } catch(Exception e) {} } void eccentricitySlider_Action(Event event) { double rrtemp; e=eccentricitySlider.getValue()/100.0; if(rr+rb>1-e) { rrtemp=(1-e)/(1+rb/rr); rb=(1-e)/(1+rr/rb); rr=rrtemp; if(rb<0.01) rb=0.01; blueRadiusText.setText(String.valueOf(rb)); blueRadiusSlider.setValue((int) (rb*100)); if(rr<0.01) rr=0.01; redRadiusText.setText(String.valueOf(rr)); redRadiusSlider.setValue((int) (rr*100)); } eccentricityText.setText(String.valueOf(e)); repaint(); } void eccentricityText_EnterHit(Event event) { try { e=Double.valueOf(eccentricityText.getText()).doubleValue(); if(e<0) { e=0; eccentricityText.setText(String.valueOf(e)); } else if(e>1) { e=0.9999999; eccentricityText.setText(String.valueOf(e)); } eccentricitySlider.setValue((int)e*100); repaint(); } catch(Exception e) {} } double mr=50,mb=50,rr=0.25,rb=0.25,lr=0.25,lb=0.5,inc=85,e=0; //double mr,mb,rr,rb,lr,lb,inc; double xr[], yr[], zr[], xb[], yb[], zb[], lite[]; int np=200,phase; void Orbit() { double m1,m2,r1,r2,l1,l2,phi; double q,ir,r1sqr,r2sqr; double x,y,z; double x1,y1,z1; double x2,y2,z2; double h,t,a1,a2; double ca1,ca2,rho,t1,t2; double hsqr; int i; if(rr>rb) { m1=mr; m2=mb; r1=rr; r2=rb; l1=lr; l2=lb; phi=Math.PI; } else { m1=mb; m2=mr; r1=rb; r2=rr; l1=lb; l2=lr; phi=0; } q=m2/m1; // Mass Ratio ir=inc*Math.PI/180; // Orbital Inclination r1sqr=r1*r1; r2sqr=r2*r2; double meanAnomaly; // Compute Star Positions and Light Curve for(i=0;iz2) a2=0; // total eclipse else a1=a1-a2; // annular eclipse } else {/* Partial Eclipses * The area covered during partial eclipses is determined * by considering and area of a circle cut by a line segment: * Area=r^2 (theta - Sin(theta)) / 2 where r is the radius * of the circle and sin(theta)=h/r. See math handbooks. */ h=r1sqr*r2sqr; h=h-(rho*rho-r1sqr-r2sqr)*(rho*rho-r1sqr-r2sqr)/4; ca1=0;ca2=0; if(h!=r2 && h!=r1 && h>=0) { hsqr=h/(rho*rho); h=Math.sqrt(hsqr); t1=2*Math.atan(h/Math.sqrt(r1sqr-hsqr)); t2=2*Math.atan(h/Math.sqrt(r2sqr-hsqr)); ca1=r1sqr*(t1-Math.sin(t1))/2; ca2=r2sqr*(t2-Math.sin(t2))/2; } if(rho>Math.sqrt(r1sqr-r2sqr)) { // Shallow Partial Eclipse if(z1>z2) a2=a2-ca1-ca2; else a1=a1-ca1-ca2; } else { // Deep Partial Eclipse if(z1>z2) a2=ca2-ca1; else a1=a1-a2+ca2-ca1; } } } // Approximate Light Intensity (no limb darkening) lite[i]=(l1*a1/r1sqr + l2*a2/r2sqr)/(4*Math.PI); if(rr>rb) { xr[i]=x1; yr[i]=y1; zr[i]=z1; xb[i]=x2; yb[i]=y2; zb[i]=z2; } else { xr[i]=x2; yr[i]=y2; zr[i]=z2; xb[i]=x1; yb[i]=y1; zb[i]=z1; } } // next i } public void init() { int points=200; super.init(); mr=ourParameter("redMass",50); mb=ourParameter("blueMass",50); rr=ourParameter("redRadius",0.25); rb=ourParameter("blueRadius",0.25); lr=ourParameter("redLuminosity",0.25); lb=ourParameter("blueLuminosity",0.5); inc=ourParameter("inclination",85); e=ourParameter("eccentricity",0); xr=new double[points]; yr=new double[points]; zr=new double[points]; xb=new double[points]; yb=new double[points]; zb=new double[points]; lite=new double[points]; //{{INIT_CONTROLS addNotify(); resize(537,350); //setLayout(new GridLayout(2,1,5,5)); setLayout(new BorderLayout(5,5)); Panel outputPanel=new Panel(); outputPanel.setLayout(new GridLayout(1,2,15,15)); Panel lightCurvePanel=new Panel(); lightCurvePanel.setLayout(new BorderLayout()); lightCurvePanel.add("North", new Label("Light Curve", Label.CENTER)); light=new lightCurveCanvas(); lightCurvePanel.add("Center",light); outputPanel.add(lightCurvePanel); Panel animationPanel=new Panel(); animationPanel.setLayout(new BorderLayout()); animationPanel.add("North", new Label("Earth Perspective", Label.CENTER)); anim=new animationCanvas(); animationPanel.add("Center",anim); outputPanel.add(animationPanel); add("Center",outputPanel); Panel inputPanel=new Panel(); inputPanel.setLayout(new GridLayout(1,3,15,15)); Panel blueStarPanel=new Panel(); blueStarPanel.setLayout(new GridLayout(7,1,2,2)); blueStarPanel.add(new Label("Blue Star", Label.CENTER)); //-----------------blue Luminosity--------------------------------- Panel blueLuminosityPanel=new Panel(); blueLuminosityPanel.setLayout(new GridLayout(1,2,1,1)); blueLuminosityPanel.add(new Label("Luminosity",Label.LEFT)); blueLuminosityText = new TextField(String.valueOf(lb),10); blueLuminosityPanel.add(blueLuminosityText); blueStarPanel.add(blueLuminosityPanel); blueLuminositySlider = new Scrollbar(Scrollbar.HORIZONTAL, (int) (lb*100), 10, 1, 100); blueStarPanel.add(blueLuminositySlider); //-----------------blue Radius------------------------------------- Panel blueRadiusPanel=new Panel(); blueRadiusPanel.setLayout(new GridLayout(1,2,1,1)); blueRadiusPanel.add(new Label("Radius",Label.LEFT)); blueRadiusText = new TextField(String.valueOf(rb),10); blueRadiusPanel.add(blueRadiusText); blueStarPanel.add(blueRadiusPanel); blueRadiusSlider = new Scrollbar(Scrollbar.HORIZONTAL, (int) (rb*100), 10, 1, 100); blueStarPanel.add(blueRadiusSlider); //-----------------blue Mass------------------------------------- Panel blueMassPanel=new Panel(); blueMassPanel.setLayout(new GridLayout(1,2,1,1)); blueMassPanel.add(new Label("Mass",Label.LEFT)); blueMassText = new TextField(String.valueOf(mb),10); blueMassPanel.add(blueMassText); blueStarPanel.add(blueMassPanel); blueMassSlider = new Scrollbar(Scrollbar.HORIZONTAL,(int)mb, 10, 1, 100); blueStarPanel.add(blueMassSlider); inputPanel.add(blueStarPanel); Panel redStarPanel=new Panel(); redStarPanel.setLayout(new GridLayout(7,1)); redStarPanel.add(new Label("Red Star", Label.CENTER)); //-----------------red Luminosity--------------------------------- Panel redLuminosityPanel=new Panel(); redLuminosityPanel.setLayout(new GridLayout(1,2,1,1)); redLuminosityPanel.add(new Label("Luminosity",Label.LEFT)); redLuminosityText = new TextField(String.valueOf(lr),10); redLuminosityPanel.add(redLuminosityText); redStarPanel.add(redLuminosityPanel); redLuminositySlider = new Scrollbar(Scrollbar.HORIZONTAL, (int) (lr*100), 10, 1, 100); redStarPanel.add(redLuminositySlider); //-----------------red Radius------------------------------------- Panel redRadiusPanel=new Panel(); redRadiusPanel.setLayout(new GridLayout(1,2,1,1)); redRadiusPanel.add(new Label("Radius",Label.LEFT)); redRadiusText = new TextField(String.valueOf(rr),10); redRadiusPanel.add(redRadiusText); redStarPanel.add(redRadiusPanel); redRadiusSlider = new Scrollbar(Scrollbar.HORIZONTAL, (int) (rr*100), 10, 1, 100); redStarPanel.add(redRadiusSlider); //-----------------red Mass------------------------------------- Panel redMassPanel=new Panel(); redMassPanel.setLayout(new GridLayout(1,2,1,1)); redMassPanel.add(new Label("Mass",Label.LEFT)); redMassText = new TextField(String.valueOf(mr),10); redMassPanel.add(redMassText); redStarPanel.add(redMassPanel); redMassSlider = new Scrollbar(Scrollbar.HORIZONTAL,(int)mr, 10, 1, 100); redStarPanel.add(redMassSlider); inputPanel.add(redStarPanel); //---------------Orbit Panel--------------------------- Panel orbitPanel=new Panel(); orbitPanel.setLayout(new GridLayout(7,1)); orbitPanel.add(new Label("Orbital Parameters", Label.CENTER)); // animateButton= new Button("Animate"); //orbitPanel.add(animateButton); Panel inclinationPanel=new Panel(); inclinationPanel.setLayout(new GridLayout(1,2,1,1)); inclinationPanel.add(new Label("Inclination",Label.LEFT)); inclinationText = new TextField(String.valueOf(inc),10); inclinationPanel.add(inclinationText); orbitPanel.add(inclinationPanel); inclinationSlider = new Scrollbar(Scrollbar.HORIZONTAL,(int)(inc+90), 10, 0, 180); orbitPanel.add(inclinationSlider); Panel eccentricityPanel=new Panel(); eccentricityPanel.setLayout(new GridLayout(1,2,1,1)); eccentricityPanel.add(new Label("Eccentricity",Label.LEFT)); eccentricityText = new TextField(String.valueOf(e),10); eccentricityPanel.add(eccentricityText); orbitPanel.add(eccentricityPanel); eccentricitySlider = new Scrollbar(Scrollbar.HORIZONTAL,(int)(e*100), 10, 0, 100); orbitPanel.add(eccentricitySlider); Panel pointsPanel=new Panel(); pointsPanel.setLayout(new GridLayout(1,2,1,1)); pointsPanel.add(new Label("Points",Label.LEFT)); pointsText = new TextField(String.valueOf(100),10); pointsPanel.add(pointsText); orbitPanel.add(pointsPanel); pointsSlider =new Scrollbar(Scrollbar.HORIZONTAL,100, 10, 10, 2000); orbitPanel.add(pointsSlider); inputPanel.add(orbitPanel); add("South",inputPanel); anim.start(); //}} } public boolean handleEvent(Event event) { // filter out non-numeric characters in all TextFields //if(event.target instanceof TextField) //{ // if(event.id!=Event.ACTION_EVENT && event.id==Event.KEY_PRESS && // (char)event.key!='.' && !Character.isDigit((char)event.key) ) // return true; //} if (event.target == blueLuminosityText && event.id == Event.ACTION_EVENT) { blueLuminosityText_EnterHit(event); return true; } //if (event.target == blueLuminositySlider && event.id == Event.ACTION_EVENT) { // blueLuminositySlider_Action(event); // return true; //} if (event.target==blueLuminositySlider) { blueLuminositySlider_Action(event); return true; } if (event.target == redLuminosityText && event.id == Event.ACTION_EVENT) { redLuminosityText_EnterHit(event); return true; } if (event.target == redLuminositySlider) { redLuminositySlider_Action(event); return true; } if (event.target == blueRadiusText && event.id == Event.ACTION_EVENT) { blueRadiusText_EnterHit(event); return true; } if (event.target == blueRadiusSlider) { blueRadiusSlider_Action(event); return true; } if (event.target == redRadiusText && event.id == Event.ACTION_EVENT) { redRadiusText_EnterHit(event); return true; } if (event.target == redRadiusSlider) { redRadiusSlider_Action(event); return true; } if (event.target == blueMassText && event.id == Event.ACTION_EVENT) { blueMassText_EnterHit(event); return true; } if (event.target == blueMassSlider) { blueMassSlider_Action(event); return true; } if (event.target == redMassText && event.id == Event.ACTION_EVENT) { redMassText_EnterHit(event); return true; } if (event.target == redMassSlider) { redMassSlider_Action(event); return true; } if (event.target == inclinationText && event.id == Event.ACTION_EVENT) { inclinationText_EnterHit(event); return true; } if (event.target == inclinationSlider) { inclinationSlider_Action(event); return true; } if (event.target == eccentricityText && event.id == Event.ACTION_EVENT) { eccentricityText_EnterHit(event); return true; } if (event.target == eccentricitySlider) { eccentricitySlider_Action(event); return true; } return super.handleEvent(event); } public void paint(Graphics g) { Orbit(); // Compute new orbit //phase=anim.phase; light.lite=lite; // pass new values to the light curve canvas light.np=np; light.repaint(); //light.phase=phase; // pass new values to the animation canvas anim.rr=rr; anim.rb=rb; anim.xr=xr; anim.xb=xb; anim.yr=yr; anim.yb=yb; anim.zr=zr; anim.zb=zb; anim.np=np; anim.inc=inc; anim.phase=light.phase; anim.repaint(); } public double ourParameter(String label, double defaultValue) { String valueString=getParameter(label); Double value; if(valueString!=null) try { value = new Double(valueString); } catch (NumberFormatException e) { value = new Double(defaultValue); } else value=new Double(defaultValue); return value.doubleValue(); } public String getAppletInfo() { return "Binary Stars\n" + "by John Talbot\n"+ "http://www.achilles.net/~jtalbot\n"; } public String[][] getParameterInfo() { String[][] info = { // Parameter Name Kind of Value Description {"redMass", "double", "Red star mass in arbitrary units (default 50)"}, {"blueMass", "double", "Blue star mass in arbitrary units (default 50)"}, {"redRadius", "double", "Red star radius in orbital radius units (default 0.25)"}, {"blueRadius", "double", "Blue star radius in orbital radius units (default 0.25)"}, {"redLuminosity", "double", "Red star luminosity in arbitrary units (default 0.25)"}, {"blueLuminosity", "double", "Blue star luminosity in arbitrary units (default 0.5)"}, {"inclination", "double", "Orbit inclination in degrees relative to line of sight (default 85)"}, {"eccentricity", "double", "Orbit eccentricity from 0 to 1 (default 0)"} }; return info; } lightCurveCanvas light; animationCanvas anim; TextField blueLuminosityText; Scrollbar blueLuminositySlider; TextField blueRadiusText; Scrollbar blueRadiusSlider; TextField blueMassText; Scrollbar blueMassSlider; TextField redLuminosityText; Scrollbar redLuminositySlider; TextField redRadiusText; Scrollbar redRadiusSlider; TextField redMassText; Scrollbar redMassSlider; TextField inclinationText; Scrollbar inclinationSlider; TextField eccentricityText; Scrollbar eccentricitySlider; TextField pointsText; Scrollbar pointsSlider; } class lightCurveCanvas extends Canvas { double lite[]; int np=200,phase=0; Image imageBuffer; //off screen image Graphics gBuffer; //Graphics context of buffer Dimension imageDim; //size of offscreen image private void resizeImage() { Dimension dim=size(); //size of animation Canvas int width=dim.width; int height=dim.height; if(imageDim!=null && imageDim.width==width && imageDim.height==height) return; imageDim=new Dimension(width,height); imageBuffer=createImage(width,height); gBuffer=imageBuffer.getGraphics(); } public void update(Graphics g) { resizeImage(); gBuffer.setColor(Color.white); // clear off-screen image gBuffer.fillRect(0,0,imageDim.width-1,imageDim.height-1); plotLightCurve(gBuffer); // create plot in off screen buffer paint(g); // repaint the image } private void plotLightCurve(Graphics g) { Dimension d=size(); int width=d.width; int height=d.height; int scale=height*92/100; int offset=height*4/100; int x,y; double min=1e23,max=-1e23; for(int i=0;imax) max=lite[i]; if(lite[i]