import java.applet.*; import java.awt.*; import java.awt.image.*; import java.lang.Math; import java.awt.event.*; import java.net.*; import java.util.*; import java.lang.*; // use the old event model to be compatible with Java 1.1.5 public class SatWorks extends Applet implements Runnable, ActionListener { Graphics gb; Image buffer; Image satImage, laloImage, worldImage; RotateGlobe rg; String param; double longi = 90.; double altitude = 20.; boolean isRotating = true; double ELEVATIONRATIO = 35.38; double KMPERPIXEL = 35.; double PERIODRATIO = 11.0; int R = 180; int panelSize; double satAng = 0.; final double pi2 = .01745329252; double declination = 15. * pi2; double swathWidth = 20.; int ratioMax = 10; // ratio of sat orbits to earth rotations int spotSize = 4; int numSpots = 5; IncDec adjustRatio, adjustSpotSize, adjustNumSpots, adjustSwathWidth, adjustInclination, adjustAltitude, adjustScanRate; Button restart, reset; boolean isLeo; int xsat, ysat, xsatcutoff; int scanRate = 4; double resetLongi, resetSatAng, resetAltitude, resetDeclination, resetSwathWidth; int resetRatioMax, resetSpotSize, resetNumSpots, resetScanRate; public void init() { setLayout(null); laloImage = loadImage("latlon2.gif"); worldImage = loadImage("world2.gif"); //satImage = loadImage("satellite.jpg"); isLeo = true; if (getParameter("geo") != null) { isLeo = false; declination = 0.; altitude = 0.; xsat = -R; ysat = R - 2; xsatcutoff = R; } if (getParameter("longitude") != null) { longi = Integer.parseInt(getParameter("longitude").trim()); } panelSize = 2 * R + 100; rg = new RotateGlobe(laloImage, worldImage,R,isLeo); rg.setSwath(declination, swathWidth, spotSize, numSpots); rg.setSize(panelSize, panelSize); // width=height = 2 * R + 100 (for orbit) // applet width = width + 120 for right-side controls buffer = createImage(panelSize,panelSize); gb = buffer.getGraphics(); int CWID = 150; if (isLeo) { adjustInclination = new IncDec(CWID,50,"Inclination = "+ ( (int)Math.round(90.- declination/pi2))+"\u00b0"); adjustInclination.setLocation(panelSize+10, 10); adjustInclination.addActionListener(this); add(adjustInclination); adjustSwathWidth = new IncDec(CWID,50,"Swath Width = " + ( (int)Math.round(2.1*swathWidth*KMPERPIXEL))+" km"); adjustSwathWidth.setLocation(panelSize+10, 60+10); adjustSwathWidth.addActionListener(this); add(adjustSwathWidth); adjustAltitude = new IncDec(CWID,50,"Altitude = "+ ( (int)Math.round(altitude*ELEVATIONRATIO)) +" km"); adjustAltitude.setLocation(panelSize+10, 2*60+10); adjustAltitude.addActionListener(this); add(adjustAltitude); adjustSpotSize = new IncDec(CWID,50,"Spot Size = "+ ( (int)Math.round(spotSize*KMPERPIXEL))+" km"); adjustSpotSize.setLocation(panelSize+10, 3*60+10); adjustSpotSize.addActionListener(this); add(adjustSpotSize); adjustNumSpots = new IncDec(CWID,50,"Number of Spots = "+numSpots); adjustNumSpots.setLocation(panelSize+10, 4*60+10); adjustNumSpots.addActionListener(this); add(adjustNumSpots); adjustRatio = new IncDec(CWID,50,"Period = "+ ( (int)Math.round(60. * PERIODRATIO/ratioMax))+" mins"); adjustRatio.setLocation(panelSize+10, 5*60+10); adjustRatio.addActionListener(this); add(adjustRatio); } else { adjustScanRate = new IncDec(CWID,50,"Scan Rate"); adjustScanRate.setLocation(panelSize+10, 10); adjustScanRate.addActionListener(this); add(adjustScanRate); } restart = new Button("Clear Image"); restart.setBounds(panelSize+10+CWID/2-90/2, 6*60+30, 90,20); restart.addActionListener(this); add(restart); reset = new Button("Reset"); reset.setBounds(panelSize+10+CWID/2-90/2, 7*60+10, 90,20); reset.addActionListener(this); resetSatAng = satAng; resetAltitude = altitude; resetDeclination = declination; resetSwathWidth = swathWidth; resetLongi = longi; resetSpotSize = spotSize; resetNumSpots = numSpots; resetRatioMax = ratioMax; resetScanRate = scanRate; add(reset); } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { gb.setColor(Color.black); gb.fillRect(0,0,panelSize,panelSize); int center = panelSize / 2; // offset of 50 lines/pixels for orbit... gb.drawImage(rg.getImage(longi),50,50,this); if (isLeo) { // increment the satellite position each time this is called satAng = satAng + 1.; if (satAng >= 180.) satAng = -satAng; ysat = (int) Math.round((R+altitude)*Math.cos(satAng*pi2) * Math.cos(declination)); xsat = (int) Math.round(ysat*Math.tan(declination)); double rr = Math.sqrt((double)ysat*ysat + (double)xsat*xsat); if ((Math.abs(rr) < R+4) && satAng < 0.0) { } else { gb.setColor(Color.black); gb.drawRect(center+xsat-2,center-ysat-2,5,5); gb.setColor(Color.white); gb.drawRect(center+xsat-1,center-ysat-1,3,3); if (Math.abs(rr) < R) rg.mapSatellite(xsat,ysat); } } else { xsat = xsat + scanRate; if (xsat > xsatcutoff) { ysat = ysat - (spotSize - (int)Math.round(spotSize/2. * Math.abs((double)ysat/R))); if (ysat < -R) { ysat = R; } xsat =(int) -Math.round( (R * Math.cos((double)ysat/R)) ); xsatcutoff = -xsat; // when to stop this line } rg.mapSatellite(xsat, ysat); } gb.setColor(Color.orange); g.drawImage(buffer,0,0,this); } // Listeners public void actionPerformed(ActionEvent e) { if (e.getSource() == adjustInclination) { adjustInclination.enableButtons(true, true); if (e.getID() == 0 ) { declination = declination+2.*pi2; if (declination > 86.*pi2) { declination = 86.*pi2; adjustInclination.enableButtons(false, true); } } else if (e.getID() == 1) { declination = declination-2.*pi2; if (declination < 0.) { declination = 0; adjustInclination.enableButtons(true, false); } } } if (e.getSource() == adjustSwathWidth) { adjustSwathWidth.enableButtons(true, true); if (e.getID() == 0 ){ swathWidth = swathWidth - 1.; if (swathWidth < 1.) { swathWidth = 1.; adjustSwathWidth.enableButtons(false, true); } } else if (e.getID() == 1) { swathWidth = swathWidth + 1.; if (swathWidth > 50.) { swathWidth = 50.; adjustSwathWidth.enableButtons(true, false); } } } if (e.getSource() == adjustAltitude) { adjustAltitude.enableButtons(true, true); if (e.getID() == 0 ){ altitude = altitude - 1.; if (altitude < 2.) { altitude = 2.; adjustAltitude.enableButtons(false, true); } else { swathWidth = swathWidth - .5; if (swathWidth < 1.0) swathWidth = 1.0; } } else if (e.getID() == 1) { altitude = altitude + 1; if (altitude > 50.) { altitude = 50.; adjustAltitude.enableButtons(true, false); } else { swathWidth = swathWidth + .5; if (swathWidth > 50.0) swathWidth = 50.; } } adjustAltitude.setText("Altitude = "+ ( (int)Math.round(altitude*ELEVATIONRATIO)) +" km"); } if (e.getSource() == adjustNumSpots) { adjustNumSpots.enableButtons(true, true); if (e.getID() == 0 ){ numSpots = numSpots - 1; if (numSpots < 1) { numSpots = 1; adjustNumSpots.enableButtons(false, true); } } else if (e.getID() == 1) { numSpots = numSpots + 1; if (numSpots > 20) { numSpots = 20; adjustNumSpots.enableButtons(true, false); } } } if (e.getSource() == adjustSpotSize) { adjustSpotSize.enableButtons(true, true); if (e.getID() == 0 ){ spotSize = spotSize - 1; if (spotSize < 1) { spotSize = 1; adjustSpotSize.enableButtons(false, true); } } else if (e.getID() == 1) { spotSize = spotSize + 1; if (spotSize > 10) { spotSize = 10; adjustSpotSize.enableButtons(true, false); } } } if (e.getSource() == adjustRatio) { adjustRatio.enableButtons(true, true); if (e.getID() == 1 ){ ratioMax = ratioMax - 1; if (ratioMax < 2) { ratioMax = 2; adjustRatio.enableButtons(true, false); } } else if (e.getID() == 0) { ratioMax = ratioMax + 1; if (ratioMax > 32) { ratioMax = 32; adjustRatio.enableButtons(false, true); } } } if (e.getSource() == adjustScanRate) { adjustScanRate.enableButtons(true, true); if (e.getID() == 0 ) { scanRate = scanRate - 1; if (scanRate < 1) { scanRate = 1; adjustScanRate.enableButtons(false, true); } } else if (e.getID() == 1) { scanRate = scanRate + 1; if (scanRate > 20) { scanRate = 20; adjustScanRate.enableButtons(true, false); } } } if (isLeo) { adjustAltitude.setText("Altitude = "+ ( (int)Math.round(altitude*ELEVATIONRATIO)) +" km"); adjustSwathWidth.setText("Swath Width = " + ( (int)Math.round(2.1*swathWidth*KMPERPIXEL))+" km"); adjustInclination.setText("Inclination = "+ ( (int)Math.round(90.- declination/pi2))+"\u00b0"); adjustNumSpots.setText("Number of Spots = "+numSpots); adjustRatio.setText("Period = "+ ( (int)Math.round(60. * PERIODRATIO/ratioMax))+" mins"); adjustSpotSize.setText("Spot Size = "+ ( (int)Math.round(spotSize*KMPERPIXEL))+" km"); } else { adjustScanRate.setText("Scan Rate "); } rg.setSwath(declination, swathWidth, spotSize, numSpots); if (e.getSource() == reset) { satAng = resetSatAng; altitude = resetAltitude; declination = resetDeclination; swathWidth = resetSwathWidth; longi = resetLongi; spotSize = resetSpotSize; numSpots = resetNumSpots; ratioMax = resetRatioMax; if (!isLeo) { xsat = -R; ysat = R; declination = 0; altitude = 0; xsatcutoff = R; scanRate = resetScanRate; } if (isLeo) { adjustAltitude.setText("Altitude = "+ ( (int)Math.round(altitude*ELEVATIONRATIO)) +" km"); adjustSwathWidth.setText("Swath Width = " + ( (int)Math.round(2.1*swathWidth*KMPERPIXEL))+" km"); adjustInclination.setText("Inclination = "+ ( (int)Math.round(90.- declination/pi2))+"\u00b0"); adjustNumSpots.setText("Number of Spots = "+numSpots); adjustRatio.setText("Period = "+ ( (int)Math.round(60. * PERIODRATIO/ratioMax))+" mins"); adjustSpotSize.setText("Spot Size = "+ ( (int)Math.round(spotSize*KMPERPIXEL))+" km"); adjustSpotSize.enableButtons(true, true); adjustInclination.enableButtons(true, true); adjustSwathWidth.enableButtons(true, true); adjustAltitude.enableButtons(true, true); adjustNumSpots.enableButtons(true, true); adjustRatio.enableButtons(true, true); } else { adjustScanRate.setText("Scan Rate "); adjustScanRate.enableButtons(true, true); } rg.setSwath(declination, swathWidth, spotSize, numSpots); rg.clearImage(); } if (e.getSource() == restart) { rg.clearImage(); } } // next, handle running a Thread to automatically repaint // the display every "refreshRate" milliseconds private Thread animator_thread = null; private boolean isRunning; int refreshRate = 20; int ratio = 0; public void start() { if (animator_thread == null) { isRunning = true; animator_thread = new Thread(this); animator_thread.start(); } } public void stop() { if ((animator_thread != null) && animator_thread.isAlive()) { isRunning = false; animator_thread.stop(); } animator_thread = null; } public void run () { while (isRunning) { try { Thread.sleep(refreshRate); if (isLeo && isRotating) { ratio = ratio + 1; if (ratio > ratioMax) { longi = longi - .5; if (longi < 0.) longi = 360.; ratio = 0; } } repaint(); } catch (Exception re) { System.out.println("#### "+re); } } } // Utilities for getting images and audio clips from JAR or URL public Image loadImage(String name) { // first try the URL Image img = null; URL u = getClass().getResource( (String) name); if (u == null) { u = getDocumentBase(); img = getImage(u,name); } else { img = getImage(u); } MediaTracker mt = new MediaTracker(this); mt.addImage(img, 0); try { mt.waitForAll(); } catch ( Exception ex ) {img = null; } return img; } } class RotateGlobe extends Component { byte[] pixels, pixWorld, pixHold; // now setup for large image (2 x lat/lon of world) int LINES=361; int ELEMS=721; final double pi2 = .01745329252; ColorModel cm; double centerlon = 0.; double declination, swathWidth; double factor; int spotSize, preferredSpots; int R, N; int[] line2lat; int[][] ele2lon; int[] swathX, swathY; Image img; MemoryImageSource mis = null; byte[] pixs; double xb, xe, yb, ye, xstep, ystep, lat, lon; int z, zz; boolean isLeo; public RotateGlobe(Image lalo, Image world, int size, boolean leo) { isLeo = leo; R = size; N = 2 * R + 1; factor = (double)R/90.; line2lat = new int[R+1]; ele2lon = new int[R+1][R+1]; try { PixelGrabber pg = new PixelGrabber(lalo,0,0,ELEMS,LINES,false); pg.grabPixels(); pixels = (byte[]) pg.getPixels(); cm = pg.getColorModel(); int stat = pg.status(); PixelGrabber pgw = new PixelGrabber(world,0,0,ELEMS,LINES,false); pgw.grabPixels(); pixWorld = (byte[]) pgw.getPixels(); pixHold = new byte[ELEMS*LINES]; stat = pgw.status(); // fix the color for the base map (0=backgnd, 1=map, 2=latlon) for (int i=0; i