/***************************** * Joseph Snow * Aspire * NightSky Applet * Dec. 2000 ****************************/ //import com.sun.java.swing.*; import javax.swing.*; //import com.sun.java.swing.event.*; import javax.swing.event.*; import java.util.*; import java.awt.*; import java.awt.event.*; import NSkyInfoPanel; import NSkySunEarthSystem; import ImageManipulator; public class SkySeasonsMixApplet extends JApplet implements ActionListener, Runnable { // The whole applets size is width: 0->700, height: 0->368 // Variables used as parameters: must be predefined here! // left frames public Rectangle nsky_bounds = new Rectangle(2, 2, 496, 298); public Rectangle datebutton_bounds = new Rectangle(2, 300, 496, 32); public Rectangle infobar_bounds = new Rectangle(2, 334, 496, 32); // right frames public Rectangle earthmap_bounds = new Rectangle(500, 2, 198, 120); // image size is 198x99 public Rectangle checkbox_bounds = new Rectangle(500, 122, 198, 106); public Rectangle sunview_bounds = new Rectangle(500, 230, 198, 136); // these are for initialization only, // the actual coordinates are maintained within the sun earth system. public final double LATITUDE = 40.542; // SLC public final double LONGITUDE = -111.883; // SLC //public final static int MAX_X = 360; // 365 days per year //public final static int MAX_Y = 90; //public final static int MAX_TIME = MAX_X; // custom variables public NightSkyComponent nightskycomponent; public NSkySunEarthSystem system; public NSkyInfoPanel nsinfoPanel; private EarthMapComponent earthmap; private NSkySunEarthView sunEarthView; private Thread thread; private ImageManipulator earthMapImage; // keep the original image around so that the earthImageMap can be played with and marked up private Image earthMapImage_org; // (i.e. longitude and latitude mark, tropic of cancer and capricorn and arctic circles) private Image earthGlobeImage; // GUI objects -- Should be private unless absolutely necessary public ButtonListener thebuttonlistener; public DateButtonListener thedatebuttonlistener; private JTextField fov_text; private JButton starPlusButton; private JButton starMinusButton; private JButton distPlusButton; private JButton distMinusButton; private JCheckBox cb1; private JCheckBox cb2; private JCheckBox cb3; public int xlong; public int ylat; public void init() { thebuttonlistener = new ButtonListener(this); int width = getSize().width; int height = getSize().height; getContentPane().setLayout(null); GregorianCalendar calendar = new GregorianCalendar(); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); system = new NSkySunEarthSystem(calendar, LATITUDE, LONGITUDE); loadImages(); getContentPane().setBackground(Color.gray); // this needs to be loaded first, becuase other components use it later nightskycomponent = new NightSkyComponent(this, nsky_bounds.x, nsky_bounds.y, nsky_bounds.width, nsky_bounds.height); getContentPane().add(nightskycomponent); earthmap = new EarthMapComponent(this, earthMapImage_org); earthmap.setBounds(earthmap_bounds); EarthMapMouseListener elistener = new EarthMapMouseListener(this, earthmap); earthmap.addMouseListener(elistener); earthmap.addMouseMotionListener(elistener); getContentPane().add(earthmap); sunEarthView = new NSkySunEarthView(system, earthGlobeImage); sunEarthView.setBounds(sunview_bounds); getContentPane().add(sunEarthView); getContentPane().add(makeCheckboxPanel()); getContentPane().add(makeDateButtonPanel(calendar)); nsinfoPanel = new NSkyInfoPanel( this ); nsinfoPanel.setBounds(infobar_bounds); getContentPane().add(nsinfoPanel); } private void loadImages() { MediaTracker tracker = new MediaTracker(this); earthMapImage_org = getImage(getCodeBase(), "images/earth.gif"); earthGlobeImage = getImage(getCodeBase(), "images/earthglobe.gif"); tracker.addImage(earthMapImage_org, 0); try { tracker.waitForAll(); earthMapImage = new ImageManipulator(this, earthMapImage_org, 0); } catch (InterruptedException e) { e.printStackTrace(); } } public JPanel makeCheckboxPanel() { // start time lapse button JPanel jpanel = new JPanel(new FlowLayout()); jpanel.setBounds(checkbox_bounds); cb1 = new JCheckBox("Show Constellation Lines"); cb2 = new JCheckBox("Show Constellation Names"); cb3 = new JCheckBox("Use New Constellations"); cb1.setActionCommand("cb 1"); cb2.setActionCommand("cb 2"); cb3.setActionCommand("cb 3"); cb1.addActionListener(thebuttonlistener); cb2.addActionListener(thebuttonlistener); cb3.addActionListener(thebuttonlistener); cb1.setSelected(this.nightskycomponent.nightskyapp.uselines); cb2.setSelected(this.nightskycomponent.nightskyapp.usenames); cb3.setSelected(this.nightskycomponent.nightskyapp.usealtlines); JLabel fov_label = new JLabel("Distance (fov angle):"); fov_text = new JTextField(String.valueOf(this.nightskycomponent.nightskyapp.fov), 5); //fov_text = new JTextField(String.valueOf(this.nightskycomponent.nightskyapp.fov)), 5); fov_text.setName("fov_text"); fov_text.setActionCommand("fov_text"); fov_text.addActionListener(thebuttonlistener); Font font = new Font("Dialog", Font.BOLD, 10); fov_label.setFont(font); fov_text.setFont(font); cb1.setFont(font); cb2.setFont(font); cb3.setFont(font); jpanel.add(fov_label); jpanel.add(fov_text); jpanel.add(cb1); jpanel.add(cb2); jpanel.add(cb3); return jpanel; } public JPanel makeDateButtonPanel( Calendar calendar ) { GregorianCalendar myCalendar = (GregorianCalendar)calendar.clone(); Insets insets = new Insets(2,1,2,1); thedatebuttonlistener = new DateButtonListener(calendar, this); // year adjustment buttons JButton yearMinusButton = new JButton("year--"); yearMinusButton.setMargin(insets); yearMinusButton.setActionCommand( "sub year" ); yearMinusButton.addActionListener( thedatebuttonlistener ); JButton yearPlusButton = new JButton( "year++" ); yearPlusButton.setMargin(insets); yearPlusButton.setActionCommand( "add year" ); yearPlusButton.addActionListener( thedatebuttonlistener ); // month adjustment buttons JButton monthMinusButton = new JButton( "month--" ); monthMinusButton.setMargin( insets ); monthMinusButton.setActionCommand( "sub month" ); monthMinusButton.addActionListener( thedatebuttonlistener ); JButton monthPlusButton = new JButton( "month++" ); monthPlusButton.setMargin( insets ); monthPlusButton.setActionCommand( "add month" ); monthPlusButton.addActionListener( thedatebuttonlistener ); // week adjustment buttons JButton weekMinusButton = new JButton( "week--" ); weekMinusButton.setMargin( insets ); weekMinusButton.setActionCommand( "sub week" ); weekMinusButton.addActionListener( thedatebuttonlistener ); JButton weekPlusButton = new JButton( "week++" ); weekPlusButton.setMargin( insets ); weekPlusButton.setActionCommand( "add week" ); weekPlusButton.addActionListener( thedatebuttonlistener ); // day adjustment buttons JButton dayPlusButton = new JButton( "day++" ); dayPlusButton.setMargin( insets ); dayPlusButton.setActionCommand( "add day" ); dayPlusButton.addActionListener( thedatebuttonlistener ); JButton dayMinusButton = new JButton( "day--" ); dayMinusButton.setMargin( insets ); dayMinusButton.setActionCommand( "sub day" ); dayMinusButton.addActionListener( thedatebuttonlistener ); // hour adjustment buttons starPlusButton = new JButton( "stars++" ); starPlusButton.setMargin( insets ); starPlusButton.setActionCommand( "add stars" ); starPlusButton.addActionListener( thedatebuttonlistener ); starMinusButton = new JButton( "stars--" ); starMinusButton.setMargin( insets ); starMinusButton.setActionCommand( "sub stars" ); starMinusButton.addActionListener( thedatebuttonlistener ); // distance adjustment buttons distPlusButton = new JButton( "dist++" ); distPlusButton.setMargin( insets ); distPlusButton.setActionCommand( "add dist" ); distPlusButton.addActionListener( thedatebuttonlistener ); distMinusButton = new JButton( "dist--" ); distMinusButton.setMargin( insets ); distMinusButton.setActionCommand( "sub dist" ); distMinusButton.addActionListener( thedatebuttonlistener ); GridLayout buttonLayout = new GridLayout( 2, 6 ); JPanel dateSelectionPanel = new JPanel( buttonLayout ); // add plus buttons on top row dateSelectionPanel.add( yearPlusButton ); dateSelectionPanel.add( monthPlusButton ); dateSelectionPanel.add( weekPlusButton ); dateSelectionPanel.add( dayPlusButton ); dateSelectionPanel.add( starPlusButton ); //dateSelectionPanel.add( distPlusButton ); // add minus buttons on bottom row dateSelectionPanel.add( yearMinusButton ); dateSelectionPanel.add( monthMinusButton ); dateSelectionPanel.add( weekMinusButton ); dateSelectionPanel.add( dayMinusButton ); dateSelectionPanel.add( starMinusButton ); //dateSelectionPanel.add( distMinusButton ); //dateSelectionPanel.setBounds(0, 390, 350, 40); dateSelectionPanel.setBackground(Color.gray); dateSelectionPanel.setBounds(datebutton_bounds); return dateSelectionPanel; } public void start() { //earthView.run(); //earthView.updateAll(); setLocation(LATITUDE, LONGITUDE); thread = new Thread(this); thread.setPriority(6); thread.start(); } public void setLocation(double latitude, double longitude) { system.setLatitude(latitude); system.setLongitude(longitude); } public Graphics getGraphicsSkyBuf() { Graphics g = getGraphics(); g.setClip(nsky_bounds.x, nsky_bounds.y, nsky_bounds.width, nsky_bounds.height); g.translate(nsky_bounds.x, nsky_bounds.y); return g; } public Graphics getGraphicsSunView() { Graphics g = getGraphics(); g.setClip(sunview_bounds.x, sunview_bounds.y, sunview_bounds.width, sunview_bounds.height); g.translate(sunview_bounds.x, sunview_bounds.y); return g; } public void run() { long store_time = System.currentTimeMillis(); while (thread == Thread.currentThread()) { long ellapsed_time; this.paintComponent(getGraphics()); nsinfoPanel.update(); ellapsed_time = (System.currentTimeMillis() - store_time); store_time = System.currentTimeMillis(); try { if (ellapsed_time < 200) thread.sleep(200 - ellapsed_time); else thread.yield(); } catch (InterruptedException e) { thread = null; } } } public void refresh() { // This is done here instead of within paintComponent directly // for a good reason. If it is done in paintComponent and then // drawn, it tends to cause it to repaint over and over again // and slow everything down. earthMapImage = new ImageManipulator(this, earthMapImage_org, 0); } public void paintComponent(Graphics g) { sunEarthView.refresh(); } // this is needed in order for applet to be non-abstract public void actionPerformed(ActionEvent e) { } public class ButtonListener implements ActionListener { private SkySeasonsMixApplet top; public ButtonListener(SkySeasonsMixApplet app) { top = app; } public void actionPerformed(ActionEvent event) { String ac = event.getActionCommand(); if (ac == fov_text.getName()) { try { Double val = new Double(fov_text.getText()); double a = val.doubleValue(); if (a < 20.0) a = 20.0; // 0.00001 is the actual min // Impose a limit of 180 degrees, 360 is possible, but doesn't look good if (a > 180.0) a = 180.0; //top.nightskycomponent.nightskyapp.fov.setText(String.valueOf(a)); //top.nightskycomponent.nightskyapp.fov.setText(String.valueOf(a)); top.nightskycomponent.nightskyapp.fov = a; top.nightskycomponent.nightskyapp.angle = a*Math.PI/180.0; fov_text.setText(String.valueOf(a)); // fov == a at this point top.nightskycomponent.nightskyapp.skyWidget.update(getGraphicsSkyBuf()); } catch (Exception e) { fov_text.setText(String.valueOf(top.nightskycomponent.nightskyapp.fov)); fov_text.selectAll(); } } else if (ac == cb1.getActionCommand()) { // show constellation lines top.nightskycomponent.nightskyapp.uselines = cb1.isSelected(); nsinfoPanel.update(); top.nightskycomponent.nightskyapp.skyWidget.update(getGraphicsSkyBuf()); } else if (ac == cb2.getActionCommand()) { // show const. names top.nightskycomponent.nightskyapp.usenames = cb2.isSelected(); nsinfoPanel.update(); top.nightskycomponent.nightskyapp.skyWidget.update(getGraphicsSkyBuf()); } else if (ac == cb3.getActionCommand()) { // use new constellations top.nightskycomponent.nightskyapp.usealtlines = cb3.isSelected(); nsinfoPanel.update(); top.nightskycomponent.nightskyapp.skyWidget.update(getGraphicsSkyBuf()); } } } public class EarthMapComponent extends JComponent { SkySeasonsMixApplet topsky; JPanel earthViewPanel; Image earth_org; ImageManipulator earth; public JLabel ylat_text; public JLabel xlong_text; int earth_width =0; int earth_height=0; public EarthMapComponent(SkySeasonsMixApplet topsky, Image earthmap) { this.topsky = topsky; this.earthViewPanel= new JPanel(new FlowLayout()); this.earthViewPanel.setBackground(Color.green); this.earth_org = earthmap; this.earth_width = earthmap.getWidth(topsky); this.earth_height = earthmap.getHeight(topsky); this.earth = new ImageManipulator(this, earthmap, 0); LatLong_to_xy(); add(makeLatLongTextPanel()); } public void refresh() { earth = new ImageManipulator(this, earth_org, 0); xy_to_LatLong(); ylat_text.setText("lat:" + (int)topsky.system.getLatitude()); xlong_text.setText("long:" + (int)topsky.system.getLongitude()); // update the skyview window as well topsky.nightskycomponent.nightskyapp.skyWidget.update(getGraphicsSkyBuf()); } public void paintComponent(Graphics g) { drawTargetLines(earth, topsky.xlong, topsky.ylat, Color.red); g.drawImage(earth.getImage(), 0, 0, this); } public void drawTargetLines(ImageManipulator image, int x, int y, Color color) { // draw horizontal line for (int i=0; i earth_width) { xlong = earth_width -1; } if (ylat < 0) { ylat = 0; } if (ylat > earth_height){ ylat = earth_height -1; } double x = (double)xlong; double y = (double)ylat; double lat = topsky.system.getLatitude(); double lon = topsky.system.getLongitude(); if (x > earth_width/2.0) { lon = (double) - ((earth_width - x) * 180.0 / (earth_width/2.0)); } else { lon = (double) (x * 180.0 / (earth_width /2.0) ); } if (y > earth_height/2.0) { lat = (double) - ( (earth_height/2.0 - (earth_height - y)) * 90.0 / (earth_height/2.0)); } else { lat = (double) ( (earth_height/2.0 - y) * 90.0 / (earth_height/2.0)); } topsky.setLocation(lat, lon); } // accesses public members of topsky and this public void LatLong_to_xy() { double lon = topsky.system.getLongitude(); double lat = topsky.system.getLatitude(); if (lon < 0) { xlong = (int) ( (360.0 + lon) * earth_width / 360.0 ); } else { xlong = (int) (lon * (double)earth_width / 360.0); } ylat = (int) ( (90.0 - lat) * earth_height / 180.0); } } public class EarthMapMouseListener implements MouseListener, MouseMotionListener { SkySeasonsMixApplet skytop; EarthMapComponent earthtop; public EarthMapMouseListener(SkySeasonsMixApplet skytop, EarthMapComponent earthtop) { this.skytop = skytop; this.earthtop = earthtop; } public void mouseClicked(MouseEvent e) { skytop.xlong = e.getX(); skytop.ylat = e.getY(); earthtop.refresh(); } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e){ } // motion listener public void mouseDragged(MouseEvent e) { skytop.xlong = e.getX(); skytop.ylat = e.getY(); earthtop.refresh(); } public void mouseMoved(MouseEvent e) { } } public class DateButtonListener implements ActionListener { private Calendar cal; private SkySeasonsMixApplet topsky; public DateButtonListener() { this.cal = system.getCalendar(); this.topsky = null; } public DateButtonListener(Calendar calendar, SkySeasonsMixApplet topsky) { this.cal = calendar; this.topsky = topsky; } private int getCalDifference(Calendar calendar, int start_time, int stop_time, boolean forwards) { int days = cal.get(Calendar.YEAR); if (days%4 == 0) { days = 366; } else { days = 365; } int dif = 0; if (forwards == true) { dif = stop_time - start_time; } else { dif = start_time - stop_time; } if (dif < 0) { // remember dif is now negative dif = (days + dif + start_time + stop_time)%days; } return dif; } public void simulate_time(int mask, int value) { cal = system.getCalendar(); int i, start_time, stop_time =0; int len; if (mask == Calendar.YEAR) { for (i=0; i<12; i++) { // loop through each month start_time = cal.get(Calendar.DAY_OF_YEAR); cal.add(Calendar.MONTH, value); system.setCalendar(cal); stop_time = cal.get(Calendar.DAY_OF_YEAR); len = getCalDifference(cal, start_time, stop_time, (value >=0)); this.topsky.sunEarthView.paintComponent(getGraphicsSunView()); this.topsky.nightskycomponent.nightskyapp.simulate_time(start_time, len, (value >=0)); } } else if (mask == Calendar.MONTH) { for (i=0; i<4; i++) { // loop through each week_of_month start_time = cal.get(Calendar.DAY_OF_YEAR); cal.add(Calendar.WEEK_OF_MONTH, value); system.setCalendar(cal); stop_time = cal.get(Calendar.DAY_OF_YEAR); len = getCalDifference(cal, start_time, stop_time, (value >=0)); this.topsky.sunEarthView.paintComponent(getGraphicsSunView()); this.topsky.nightskycomponent.nightskyapp.simulate_time(start_time, len, (value >=0)); } // ensure that an entire month is added start_time = stop_time; for (i=0; i<4; i++) { cal.add(Calendar.WEEK_OF_MONTH, -value); } cal.add(Calendar.MONTH, value); system.setCalendar(cal); stop_time = cal.get(Calendar.DAY_OF_YEAR); len = getCalDifference(cal, start_time, stop_time, (value >=0)); this.topsky.sunEarthView.paintComponent(getGraphicsSunView()); this.topsky.nightskycomponent.nightskyapp.simulate_time(start_time, len, (value >=0)); } else if (mask == Calendar.DAY_OF_WEEK) { // simply add value start_time = cal.get(Calendar.DAY_OF_YEAR); cal.add(Calendar.DAY_OF_WEEK, value); system.setCalendar(cal); stop_time = cal.get(Calendar.DAY_OF_YEAR); len = getCalDifference(cal, start_time, stop_time, (value >=0)); this.topsky.sunEarthView.paintComponent(getGraphicsSunView()); this.topsky.nightskycomponent.nightskyapp.simulate_time(start_time, len, (value >=0)); } } public void actionPerformed(ActionEvent e) { Graphics g; String command = e.getActionCommand(); if ( command == "add year" ){ simulate_time(Calendar.YEAR, 1); } else if ( command == "sub year" ){ simulate_time(Calendar.YEAR, -1); } else if ( command == "add month" ){ simulate_time(Calendar.MONTH, 1); } else if ( command == "sub month" ){ simulate_time(Calendar.MONTH, -1); } else if ( command == "add week" ){ simulate_time(Calendar.DAY_OF_WEEK, 7); } else if ( command == "sub week" ){ simulate_time(Calendar.DAY_OF_WEEK, -7); } else if ( command == "add day" ){ simulate_time(Calendar.DAY_OF_WEEK, 1); } else if ( command == "sub day" ){ simulate_time(Calendar.DAY_OF_WEEK, -1); } else if ( command == "add stars" ){ if (this.topsky.nightskycomponent.nightskyapp.speed < this.topsky.nightskycomponent.nightskyapp.loadedlists) { this.topsky.nightskycomponent.nightskyapp.usestars = this.topsky.nightskycomponent.nightskyapp.starlists[this.topsky.nightskycomponent.nightskyapp.speed++]; this.topsky.nightskycomponent.nightskyapp.skyWidget.update(getGraphicsSkyBuf()); } if (this.topsky.nightskycomponent.nightskyapp.speed == this.topsky.nightskycomponent.nightskyapp.loadedlists) { starPlusButton.setText("Max Shown!"); } starMinusButton.setText("stars--"); } else if ( command == "sub stars" ){ if (this.topsky.nightskycomponent.nightskyapp.speed > 1) { this.topsky.nightskycomponent.nightskyapp.usestars = this.topsky.nightskycomponent.nightskyapp.starlists[--this.topsky.nightskycomponent.nightskyapp.speed -1]; this.topsky.nightskycomponent.nightskyapp.skyWidget.update(getGraphicsSkyBuf()); } if (this.topsky.nightskycomponent.nightskyapp.speed == 1) { starMinusButton.setText("Min Shown!"); } starPlusButton.setText("stars++"); } else if ( command == "add dist" ){ this.topsky.nightskycomponent.nightskyapp.skyWidget.update(getGraphicsSkyBuf()); } else if ( command == "sub dist" ){ this.topsky.nightskycomponent.nightskyapp.skyWidget.update(getGraphicsSkyBuf()); } else { system.getCalendar().set(Calendar.MONTH, cal.get(Calendar.MONTH)); system.getCalendar().set(Calendar.DAY_OF_MONTH, cal.get(Calendar.DAY_OF_MONTH)); } nsinfoPanel.update(); sunEarthView.refresh(); sunEarthView.repaint(); } } public String getDate_str() { Calendar cal = system.getCalendar(); StringBuffer date_str = new StringBuffer(cal.getTime().toString()); date_str.setLength(8); // strip off time date_str.append(cal.get(Calendar.DAY_OF_MONTH) + " " + cal.get(Calendar.YEAR) + " "); return date_str.toString(); } }