import java.awt.*; import java.awt.image.*; import java.*; import java.net.*; import java.applet.*; import java.awt.event.*; import java.util.Random; import java.lang.System; public class Hurr extends Applet implements MouseListener, MouseMotionListener, ActionListener, AdjustmentListener, KeyListener { Random rand; AnimIt animThread; Image bubbleImage; Image[] hurrback; int[][] hurrtemps; int season = 0; int showSeasonCount = 20; int hurrIndex; double xHurr, yHurr; int xHi, yHi; boolean isDraggingHi = false; boolean isDraggingLo = false; int hurrWidth = 320; int hurrHeight = 240; int cat = 0; double category = 0.; double dcat = 0.; double sizeHurr; Image[][] hurricane; String[] catnames = {"-as.gif","-bs.gif","-cs.gif","-ds.gif"}; Font labelFont, hiFont, loFont, tFont; FontMetrics fm; boolean debug = false; boolean isManual = true; boolean automove = false; boolean toggleManual = true; boolean showTemp = false; boolean tempUnitC = true; boolean toggleTemp = true; boolean showHigh = true; boolean showReset = true; int heightReset = 0; int widthReset = 0; String sReset = "Reset"; boolean enableDebug = false; boolean toggleSeason = true; boolean clickSeason = true; boolean showWinds = false; boolean toggleCategory = true; boolean okayToDrag = true; double temperature = 0; final double hurrScale = 10.; double[] xloc, yloc, dx, dy; double[][] ucomp, vcomp; boolean doingSeasons = true; final double R = 175.; final double R2 = R*R; final double WSCALE = 3.; String[] seaname = {"Winter","Spring","Summer","Fall"}; String[] hurrbase = {"images/big-hurrbase-dec.gif","images/big-hurrbase-mar.gif","images/big-hurrbase-june.gif","images/big-hurrbase-sept.gif"}; //String[] hurrbase = {"hurrbase-dec.gif","hurrbase-mar.gif","hurrbase-june.gif","hurrbase-sept.gif"}; //Gray Shades 1-149 represent SST values 270-305K //Gray Shades 150-255 represent heights of 0-4000 meters. public void init() { rand = new Random(); makeWinds(); reset(); labelFont = new Font("sans",Font.BOLD,22); hiFont = new Font("serif",Font.BOLD,50); loFont = new Font("serif",Font.BOLD,30); tFont = new Font("sansserif",Font.BOLD,16); fm = getFontMetrics(labelFont); hurrback = new Image[4]; hurrtemps = new int[4][]; String stemp = getParameter("show_sst"); String utemp = getParameter("sst_unit"); if (utemp == null) utemp = "c"; if (stemp == null) { showTemp = false; toggleTemp = true; } else { if (stemp.equalsIgnoreCase("toggle")) { showTemp = false; toggleTemp = true; } else if (stemp.equalsIgnoreCase("true")) { showTemp = true; toggleTemp = false; if (utemp.equalsIgnoreCase("c")) { tempUnitC = true; } else { tempUnitC = false; } } else if (stemp.equalsIgnoreCase("false")) { showTemp = false; toggleTemp = false; } } stemp = getParameter("auto_move"); if (stemp == null) { toggleManual = true; isManual = true; automove = false; } else if (stemp.equalsIgnoreCase("toggle")) { toggleManual = true; isManual = true; automove = false; } else if (stemp.equalsIgnoreCase("true")) { toggleManual = false; isManual = false; automove = true; } else { toggleManual = false; isManual = true; automove = false; } stemp = getParameter("show_high"); if (stemp == null) { showHigh = true; } else { if (stemp.equalsIgnoreCase("true")) { showHigh = true; } else { showHigh = false; } } stemp = getParameter("show_reset"); if (stemp == null) { showReset = true; } else { if (stemp.equalsIgnoreCase("true")) { showReset = true; } else { showReset = false; } } stemp = getParameter("change_season"); utemp = getParameter("starting_season"); if (utemp == null) { season = 3; } else if (utemp.equalsIgnoreCase("winter")) { season = 0; } else if (utemp.equalsIgnoreCase("spring")) { season = 1; } else if (utemp.equalsIgnoreCase("summer")) { season = 2; } else if (utemp.equalsIgnoreCase("fall")) { season = 3; } // just to get the initial values set System.arraycopy(ucomp[season],0,dx,0,dx.length); System.arraycopy(vcomp[season],0,dy,0,dy.length); if (stemp == null) { toggleSeason = true; clickSeason = false; } else if (stemp.equalsIgnoreCase("click")) { toggleSeason = false; clickSeason = true; } else if (stemp.equalsIgnoreCase("toggle")) { toggleSeason = true; clickSeason = false; } else { toggleSeason = false; clickSeason = false; } stemp = getParameter("enable_debug"); if (stemp == null) { enableDebug = false; debug = false; } else { if (stemp.equalsIgnoreCase("true")) { enableDebug = true; debug = true; } else if (stemp.equalsIgnoreCase("toggle")) { enableDebug = true; debug = false; } else { enableDebug = false; debug = false; } } stemp = getParameter("show_winds"); if (stemp == null) { showWinds = false; } else if (stemp.equalsIgnoreCase("true")) { showWinds = true; } else if (stemp.equalsIgnoreCase("false")) { showWinds = false; } stemp = getParameter("toggle_category"); if (stemp == null) { toggleCategory = true; } else if (stemp.equalsIgnoreCase("true")) { toggleCategory = true; } else if (stemp.equalsIgnoreCase("false")) { toggleCategory = false; } try { GetImageFile gif = new GetImageFile(this); //URL eturl = new URL(getDocumentBase(),"HURRBASE.ET"); URL eturl = gif.getFile("HURRBASE.ET"); EnhancementTable et = new EnhancementTable(eturl); hurricane = new Image[6][4]; Image bb = gif.getImage("bubble.gif"); bubbleImage = new TransparentImage(this,bb,50,0).getImage(); for (int k=0; k<4; k++) { hurrback[k] = gif.getImage(hurrbase[k]); hurrtemps[k] = new int[640 * 480]; PixelGrabber pg = new PixelGrabber(hurrback[k],0,0,640,480,hurrtemps[k],0,640); pg.grabPixels(); int stat = pg.status(); for (int i=0; i<640*480; i++) { int v = et.getIndex(hurrtemps[k][i]); if (v < 1 || v > 149) v = 0; hurrtemps[k][i] = v; } } for (int k=0; k<6; k++) { for (int i=0; i<4; i++) { Image img = gif.getImage("cat"+(k)+catnames[i]); hurricane[k][i] = new TransparentImage(this,img,100,55).getImage(); } } } catch (Exception erx) { System.out.println("#### Cannot initialize: "+erx); return; } addMouseMotionListener(this); addMouseListener(this); addKeyListener(this); reset(); animThread = new AnimIt(this); animThread.start(); requestFocus(); } public void reset() { // reset initial size, location, etc. xHurr = 540; yHurr = 345; if (showHigh) { xHi = 370; yHi = 225; } else { xHi = 0; yHi = 0; } sizeHurr = .3; category = 0.; cat = 0; } public void actionPerformed(ActionEvent e) { repaint(); } public void adjustmentValueChanged(AdjustmentEvent e) { } public void itemStateChanged(ItemEvent e) { repaint(); } public void mouseClicked(MouseEvent e) { } public void mouseEntered(MouseEvent e) {;} public void mouseExited(MouseEvent e) {;} public void mouseReleased(MouseEvent e) { isDraggingHi = false; isDraggingLo = false; okayToDrag = true; } public void mousePressed(MouseEvent e) { if (showReset) { if (e.getX() >15 && e.getX() < widthReset+15 && e.getY() < 33 && e.getY() > 33-heightReset) { okayToDrag = false; reset(); return; } } if (clickSeason) { if (e.getX() > 500 && e.getX() < 600 && e.getY() < 30 && e.getY() > 0) { season = season + 1; if (season > 3) season = 0; okayToDrag = false; interpWinds(); repaint(); return; } } if (okayToDrag && showHigh) { if (Math.abs(xHi - e.getX()) < 120 && Math.abs(yHi - e.getY()) < 120) { isDraggingHi = true; } else { isDraggingHi = false; } } } public void mouseMoved(MouseEvent e) {;} public void mouseDragged(MouseEvent e) { if (isDraggingHi) { xHi = e.getX(); yHi = e.getY(); interpWinds(); } else if (okayToDrag) { int xx = e.getX(); int yy = e.getY(); if (clickSeason && (xx > 500 && xx < 600 && yy < 30) && (Math.abs(xx - xHurr) > 3 && Math.abs(yy - yHurr) > 3) ) { return; } isDraggingLo = true; xHurr = xx; yHurr = yy; if (xHurr < 0.) xHurr = 0.; if (yHurr < 0.) yHurr = 0.; if (xHurr > 639.) xHurr = 639.; if (yHurr > 479.) yHurr = 479.; } repaint(); } void interpWinds() { // now recompute the wind field System.arraycopy(ucomp[season],0,dx,0,dx.length); System.arraycopy(vcomp[season],0,dy,0,dy.length); double dist = 0.; double weight = 0.; double xdist = 0.; double ydist = 0.; for (int i=0; i R2) continue; // outside of influence dist = Math.sqrt(dist); weight = 1. - dist/R; dx[i] = -WSCALE*ydist/R * weight + (1.-weight)*dx[i]; dy[i] = WSCALE*xdist/R * weight + (1.-weight)*dy[i]; } } public void getCategory() { final double changeRate = 20.; double avg = 0.; int size2 = 5; double cnt = 0; int pv, xx, yy, rgba; int v; temperature = -999.; for (int x=-size2; x 639) xx = 639; for (int y=-size2; y 479) yy = 479; v = hurrtemps[season][640*yy+xx]; avg = avg + v; cnt = cnt + 1; if (x == 0 && y == 0 && v > 0 && v < 150) { temperature = (270. + (307 - 270)*(v - 1.)/(149. - 1.)) - 273.15; } } } //Gray Shades 1-149 represent SST values 270-305K // 123 is about 26.5 degrees C double targetCat = 6.4*((avg/cnt) - 123.)/(149. - 123.); if (debug) System.out.println("#### avg, cnt = "+(avg/cnt)+" "+cnt+ " temp="+temperature); if (targetCat < 0.) targetCat = 0.; dcat = (targetCat - category)/changeRate; category = category + dcat; sizeHurr = sizeHurr + dcat/6.; if (sizeHurr < .3) sizeHurr = .3; if (sizeHurr > 1.3) sizeHurr = 1.3; cat = (int)category; if (debug) System.out.println("#### cat = "+(float)category +" targ="+(float)targetCat+" size = "+(float)sizeHurr); } public void moveIt() { double sumdx = 0.; double sumdy = 0.; double sumw = 0; double w = 0; if (!isManual && automove && !isDraggingLo) { for (int i=0; i 800 || yHurr < -100 || yHurr > 600 ) reset(); } //is it too close to H? if (showHigh) { double dh = (yHurr - yHi)*(yHurr - yHi) + (xHurr - xHi)*(xHurr - xHi); if (dh < 150.*150.) { double theta = Math.atan2(yHurr - yHi,xHurr - xHi); double newx = 150. * Math.cos(theta); double newy = 150. * Math.sin(theta); xHurr = xHi + newx; yHurr = yHi + newy; } } // toggle off to keep the rate steady in case of multiple repaints automove = false; } public synchronized void paint(Graphics g) { moveIt(); if (!isDraggingHi) getCategory(); Image buff = createImage(640,480); Graphics bg = buff.getGraphics(); bg.drawImage(hurrback[season],0,0,null); int hw = (int)Math.round(hurrWidth * sizeHurr); int hh = (int)Math.round(hurrHeight * sizeHurr); bg.drawImage(hurricane[cat][hurrIndex], (int)Math.round(xHurr-hw/2), (int)Math.round(yHurr-hh/2) ,hw, hh,null); bg.setFont(labelFont); String c = cat+" "; if (cat == 0) { bg.setFont(loFont); c = "L"; } bg.drawString(c,(int)Math.round(xHurr)-15,(int)Math.round(yHurr)+10); if (showTemp) { bg.setFont(tFont); String ct = "SST="+( (int)Math.round(temperature))+"\u00b0C"; if (!tempUnitC) { ct = "SST="+( (int)Math.round((9.*temperature/5.+32.)))+"\u00b0F"; } if (temperature < -900.) ct = " "; bg.drawString(ct, (int)Math.round(xHurr)-30,(int)Math.round(yHurr)+30); } if (clickSeason || showSeasonCount > 0) { // if clickSeason, always show bg.setFont(labelFont); bg.setColor(Color.black); bg.drawString(seaname[season], 512, 32); bg.setColor(Color.white); bg.drawString(seaname[season], 510, 30); bg.setColor(Color.black); showSeasonCount --; } if (showSeasonCount < 0) showSeasonCount = 0; if (showHigh) { bg.setFont(hiFont); bg.drawImage(bubbleImage,xHi-150,yHi-150,300,300,null); bg.drawString("H",xHi-20, yHi+20); } if (showWinds) { // show vectors bg.setColor(Color.white); for (int i=0; i 3) season = 0; showSeasonCount = 10; interpWinds(); } repaint(); } public void keyReleased(KeyEvent e) {} public void keyTyped(KeyEvent e) {} public void update(Graphics g) { paint(g); } public void nextStep(int hi) { automove = true; hurrIndex = hi; repaint(); } public void stop() { if (animThread != null) animThread.quitIt(); } public void makeWinds() { //datasource=dods://nomad3.ncep.noaa.gov:9090/dods/reanalyses/reanalysis-2/month/pgb/pgb.anl.climo // used month=Mar, Jun, Sep, Dec // used level=850mb //{season, level=1, lat, lon} double [] latitude={0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0}; double [] longitude={260.0, 270.0, 280.0, 290.0, 300.0, 310.0, 320.0, 330.0, 340.0, 350.0}; double [][][][] ugrid = { { { {-5.2, -4.41, -3.31, -7.13, -8.27, -8.19, -8.84, -7.73, -6.35, -4.42}, {-6.72, -5.87, -4.11, -5.93, -7.04, -6.45, -5.82, -4.72, -4.71, -2.01}, {0.59, -1.64, -2.77, -3.65, -3.83, -4.42, -5.18, -4.1, -1.22, -2.0}, {2.77, 4.43, 5.18, 5.5, 5.22, 3.59, 1.51, -0.27, -0.75, 1.52}, {2.42, 5.65, 6.84, 7.72, 8.94, 9.43, 7.91, 5.57, 3.27, 1.52}, {2.9, 3.41, 3.89, 3.05, 3.63, 5.95, 7.86, 8.7, 8.89, 7.5}, {3.79, 4.43, 4.5, 4.35, 3.43, 2.66, 3.93, 6.58, 6.94, 6.33} } }, { { {-5.61, -5.35, -6.49, -8.18, -9.4, -9.7, -9.33, -8.16, -7.82, -5.88}, {-1.6, -1.83, -4.28, -8.86, -10.46, -9.12, -8.16, -5.88, -3.78, -0.71}, {-0.68, -5.19, -5.95, -5.61, -6.53, -6.82, -6.7, -5.14, -1.97, -3.04}, {-2.02, 1.32, 2.26, 3.55, 2.96, 1.24, -0.36, -1.41, -1.3, 2.29}, {1.01, 4.31, 4.98, 5.61, 8.0, 7.94, 6.2, 4.02, 2.13, 1.23}, {2.41, 3.91, 4.71, 3.83, 4.2, 5.8, 7.11, 6.69, 6.04, 4.19}, {1.65, 1.93, 1.89, 1.83, 1.18, -0.21, 0.07, 2.19, 2.54, 2.82} } }, { { {-4.91, -4.03, -4.26, -7.9, -8.9, -9.3, -8.9, -7.1, -6.38, -3.83}, {-0.02, -1.48, -2.78, -5.56, -6.46, -5.37, -4.92, -3.22, -2.3, -1.79}, {-1.4, -3.84, -4.91, -5.49, -6.34, -6.41, -6.7, -6.1, -4.03, -3.61}, {-2.22, -.16, -0.39, 0.45, 0.51, -0.24, -0.79, -1.4, -0.85, 2.01}, {1.83, 4.57, 4.78, 5.05, 5.92, 6.4, 5.61, 4.38, 3.21, 1.81}, {4.04, 6.07, 7.08, 6.38, 6.6, 7.57, 8.47, 8.15, 7.44, 5.32}, {2.96, 2.91, 3.31, 3.27, 2.84, 1.49, 1.36, 3.36, 4.24, 5.21} } }, { { {-5.79, -3.91, -2.49, -7.55, -8.6, -9.61, -10.76, -10.15, -9.02, -6.17}, {-9.53, -7.53, -6.35, -7.96, -8.5, -8.38, -8.41, -7.08, -5.79, -5.01}, {-1.31, -3.65, -4.33, -5.1, -4.86, -4.69, -5.35, -4.83, -2.95, -3.49}, {3.68, 5.12, 4.92, 5.01, 4.25, 3.22, 1.93, 0.55, -0.39, 0.61}, {4.74, 7.99, 9.33, 9.14, 10.15, 10.32, 9.5, 7.89, 5.62, 3.23}, {5.97, 6.49, 6.76, 5.56, 5.84, 8.26, 9.43, 9.92, 9.64, 7.71}, {4.14, 4.22, 4.05, 4.58, 3.41, 1.85, 1.93, 4.29, 5.42, 6.17} } } }; double [][][][] vgrid = { { { {-0.5, -0.71, -0.7, -3.96, -5.92, -4.43, -1.12, -0.47, -0.66, 0.06}, {-0.23, -1.61, -4.58, -0.21, -1.41, -1.75, -0.94, 0.26, -0.01, -1.73}, {0.8, 2.12, 1.14, 0.93, 0.54, -0.27, -1.42, -2.68, -1.31, -1.02}, {2.42, 1.61, 1.42, 1.61, 1.83, 1.63, 0.63, -1.49, -2.55, -0.37}, {-0.98, 0.35, -0.02, -0.76, 2.49, 4.14, 4.0, 1.83, -0.44, -1.21}, {-1.96, -1.55, -1.89, -1.65, -0.66, 2.44, 4.33, 4.05, 1.82, 0.21}, {-2.35, -3.84, -1.38, -1.19, -2.1, -0.32, 0.42, 3.35, 3.51, 2.2} } }, { { {2.11, 1.69, 2.93, 2.56, 0.66, 1.25, 2.57, 1.88, 2.24, 1.85}, {0.41, 1.11, 1.6, 3.18, 0.28, 0.1, -0.22, -0.1, 0.71, -0.04}, {0.85, 2.97, 2.61, 2.99, 1.04, -0.57, -1.93, -3.14, -2.71, -2.43}, {6.44, 1.35, 0.32, 2.89, 2.31, 1.11, -0.39, -2.44, -4.67, -2.63}, {3.16, 0.81, -0.3, -0.84, 2.66, 3.0, 2.03, -0.61, -3.02, -1.39}, {0.07, -0.1, -1.3, -0.24, -0.28, 2.36, 3.32, 1.7, 0.09, -0.39}, {-1.16, -3.28, -1.39, -0.39, -0.4, 1.75, 0.85, 1.64, 1.6, 0.87} } }, { { {1.72, 1.0, 1.61, 1.3, 0.02, 1.05, 3.44, 2.54, 1.86, 0.14}, {0.43, 1.2, 1.26, 3.55, 0.95, -0.2, -0.94, -0.92, 0.13, -0.62}, {-0.66, 1.29, 1.69, 1.78, 0.93, 0.37, -0.75, -1.74, -0.66, -2.02}, {3.82, 1.89, 0.69, 1.47, 1.46, 0.98, 0.09, -1.58, -3.36, -0.98}, {2.58, 0.82, 0.01, -0.37, 1.45, 1.53, 1.37, -0.67, -1.49, -0.55}, {-0.89, -0.37, -0.19, 0.37, 0.13, 0.97, 1.62, 1.52, 1.4, 0.88}, {-1.91, -3.6, -0.76, 0.53, -0.46, 0.24, -0.34, 1.2, 2.41, 2.3} } }, { { {-0.26, -0.38, -0.34, -4.14, -4.37, -2.68, 0.14, -0.18, -1.08, -0.98}, {-1.18, -2.78, -4.18, -0.14, -1.16, -0.79, -0.36, 0.43, 0.25, -1.27}, {-0.38, 0.37, 0.12, 0.33, -0.35, -0.14, -0.47, -1.62, -1.24, -0.62}, {1.59, 1.01, 1.48, 1.14, 0.77, 0.98, 0.89, -0.43, -1.43, 0.07}, {-2.3, -0.35, 0.03, -0.28, 1.79, 2.86, 3.2, 2.69, 0.94, -0.19}, {-3.43, -2.01, -0.32, -1.18, -0.62, 1.63, 3.29, 5.09, 3.94, 2.36}, {-3.81, -4.22, 0.28, -0.09, -1.98, -0.87, 0.53, 4.09, 5.46, 3.74} } } }; int n = latitude.length * longitude.length; xloc = new double[n]; yloc = new double[n]; ucomp = new double[4][n]; vcomp = new double[4][n]; dx = new double[n]; dy = new double[n]; double centerLat = 30.0; double centerLon = 360. - 55.0; double centerLine = 480./2.; double centerEle = 640./2.; double res = 15.0; int k = 0; for (int i=0; i 3) { hurrIndex = 0; } mom.nextStep(hurrIndex); } } }